]> Pileus Git - ~andy/gtk/blob - glib/gerror.c
forgot to set the initial `0' cursor.
[~andy/gtk] / glib / gerror.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <signal.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/time.h>
23 #include <sys/times.h>
24 #include <sys/types.h>
25
26 #include <time.h>
27 #include <unistd.h>
28 #include "glib.h"
29
30 #ifdef HAVE_SYS_SELECT_H
31 #include <sys/select.h>
32 #endif /* HAVE_SYS_SELECT_H */
33
34 #ifdef STDC_HEADERS
35 #include <string.h> /* for bzero on BSD systems */
36 #endif
37
38 #define INTERACTIVE 0
39 #define STACK_TRACE 1
40
41
42 #ifndef NO_FD_SET
43 #  define SELECT_MASK fd_set
44 #else
45 #  ifndef _AIX
46      typedef long fd_mask;
47 #  endif
48 #  if defined(_IBMR2)
49 #    define SELECT_MASK void
50 #  else
51 #    define SELECT_MASK int
52 #  endif
53 #endif
54
55
56 static int  do_query (char *prompt);
57 static void debug (char *progname, int method);
58 static void stack_trace (char **);
59 static void stack_trace_sigchld (int);
60
61
62 static int stack_trace_done;
63
64 void
65 g_debug (char *progname)
66 {
67   char buf[32];
68
69   fprintf (stdout, "[n]othing, [e]xit, [s]tack trace, [a]ttach to process: ");
70   fflush (stdout);
71
72   fgets (buf, 32, stdin);
73   if (strcmp (buf, "n\n") == 0)
74     return;
75   else if (strcmp (buf, "s\n") == 0)
76     debug (progname, STACK_TRACE);
77   else if (strcmp (buf, "a\n") == 0)
78     debug (progname, INTERACTIVE);
79   else
80     exit (0);
81 }
82
83 void
84 g_attach_process (char *progname, int query)
85 {
86   if (!query || do_query ("attach to process"))
87     debug (progname, INTERACTIVE);
88 }
89
90 void
91 g_stack_trace (char *progname, int query)
92 {
93   if (!query || do_query ("print stack trace"))
94     debug (progname, STACK_TRACE);
95 }
96
97 static int
98 do_query (char *prompt)
99 {
100   char buf[32];
101
102   fprintf (stdout, "%s (y/n) ", prompt);
103   fflush (stdout);
104
105   fgets (buf, 32, stdin);
106   if ((strcmp (buf, "yes\n") == 0) ||
107       (strcmp (buf, "y\n") == 0) ||
108       (strcmp (buf, "YES\n") == 0) ||
109       (strcmp (buf, "Y\n") == 0))
110     return TRUE;
111
112   return FALSE;
113 }
114
115 static void
116 debug (char *progname,
117        int   method)
118 {
119   pid_t pid;
120   char buf[16];
121   char *args[4] = { "gdb", NULL, NULL, NULL };
122   volatile int x;
123
124   sprintf (buf, "%d", (int) getpid ());
125
126   args[1] = progname;
127   args[2] = buf;
128
129   switch (method)
130     {
131     case INTERACTIVE:
132       fprintf (stdout, "pid: %s\n", buf);
133       break;
134     case STACK_TRACE:
135       pid = fork ();
136       if (pid == 0)
137         {
138           stack_trace (args);
139           _exit (0);
140         }
141       else if (pid == (pid_t) -1)
142         {
143           perror ("could not fork");
144           return;
145         }
146       break;
147     }
148
149   x = 1;
150   while (x)
151     ;
152 }
153
154 static void
155 stack_trace (char **args)
156 {
157   pid_t pid;
158   int in_fd[2];
159   int out_fd[2];
160   SELECT_MASK fdset;
161   SELECT_MASK readset;
162   struct timeval tv;
163   int sel, index, state;
164   char buffer[256];
165   char c;
166
167   stack_trace_done = 0;
168   signal (SIGCHLD, stack_trace_sigchld);
169
170   if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
171     {
172       perror ("could open pipe");
173       _exit (0);
174     }
175
176   pid = fork ();
177   if (pid == 0)
178     {
179       close (0); dup (in_fd[0]);   /* set the stdin to the in pipe */
180       close (1); dup (out_fd[1]);  /* set the stdout to the out pipe */
181       close (2); dup (out_fd[1]);  /* set the stderr to the out pipe */
182
183       execvp (args[0], args);      /* exec gdb */
184       perror ("exec failed");
185       _exit (0);
186     }
187   else if (pid == (pid_t) -1)
188     {
189       perror ("could not fork");
190       _exit (0);
191     }
192
193   FD_ZERO (&fdset);
194   FD_SET (out_fd[0], &fdset);
195
196   write (in_fd[1], "backtrace\n", 10);
197   write (in_fd[1], "p x = 0\n", 8);
198   write (in_fd[1], "quit\n", 5);
199
200   index = 0;
201   state = 0;
202
203   while (1)
204     {
205       readset = fdset;
206       tv.tv_sec = 1;
207       tv.tv_usec = 0;
208
209       sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
210       if (sel == -1)
211         break;
212
213       if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
214         {
215           if (read (out_fd[0], &c, 1))
216             {
217               switch (state)
218                 {
219                 case 0:
220                   if (c == '#')
221                     {
222                       state = 1;
223                       index = 0;
224                       buffer[index++] = c;
225                     }
226                   break;
227                 case 1:
228                   buffer[index++] = c;
229                   if ((c == '\n') || (c == '\r'))
230                     {
231                       buffer[index] = 0;
232                       fprintf (stdout, "%s", buffer);
233                       state = 0;
234                       index = 0;
235                     }
236                   break;
237                 default:
238                   break;
239                 }
240             }
241         }
242       else if (stack_trace_done)
243         break;
244     }
245
246   close (in_fd[0]);
247   close (in_fd[1]);
248   close (out_fd[0]);
249   close (out_fd[1]);
250   _exit (0);
251 }
252
253 static void
254 stack_trace_sigchld (int signum)
255 {
256   stack_trace_done = 1;
257 }