]> Pileus Git - ~andy/gtk/blob - glib/gerror.c
Initial revision
[~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 <sys/time.h>
22 #include <sys/times.h>
23 #include <sys/types.h>
24
25 #include <time.h>
26 #include <unistd.h>
27 #include "glib.h"
28
29 #ifdef HAVE_SYS_SELECT_H
30 #include <sys/select.h>
31 #endif /* HAVE_SYS_SELECT_H */
32
33 #ifdef STDC_HEADERS
34 #include <string.h> /* for bzero on BSD systems */
35 #endif
36
37 #define INTERACTIVE 0
38 #define STACK_TRACE 1
39
40
41 #ifndef NO_FD_SET
42 #  define SELECT_MASK fd_set
43 #else
44 #  ifndef _AIX
45      typedef long fd_mask;
46 #  endif
47 #  if defined(_IBMR2)
48 #    define SELECT_MASK void
49 #  else
50 #    define SELECT_MASK int
51 #  endif
52 #endif
53
54
55 static int  do_query (char *prompt);
56 static void debug (char *progname, int method);
57 static void stack_trace (char **);
58 static void stack_trace_sigchld (int);
59
60
61 static int stack_trace_done;
62
63 void
64 g_debug (char *progname)
65 {
66   char buf[32];
67
68   fprintf (stdout, "[n]othing, [e]xit, [s]tack trace, [a]ttach to process: ");
69   fflush (stdout);
70
71   fgets (buf, 32, stdin);
72   if (strcmp (buf, "n\n") == 0)
73     return;
74   else if (strcmp (buf, "s\n") == 0)
75     debug (progname, STACK_TRACE);
76   else if (strcmp (buf, "a\n") == 0)
77     debug (progname, INTERACTIVE);
78   else
79     exit (0);
80 }
81
82 void
83 g_attach_process (char *progname, int query)
84 {
85   if (!query || do_query ("attach to process"))
86     debug (progname, INTERACTIVE);
87 }
88
89 void
90 g_stack_trace (char *progname, int query)
91 {
92   if (!query || do_query ("print stack trace"))
93     debug (progname, STACK_TRACE);
94 }
95
96 static int
97 do_query (char *prompt)
98 {
99   char buf[32];
100
101   fprintf (stdout, "%s (y/n) ", prompt);
102   fflush (stdout);
103
104   fgets (buf, 32, stdin);
105   if ((strcmp (buf, "yes\n") == 0) ||
106       (strcmp (buf, "y\n") == 0) ||
107       (strcmp (buf, "YES\n") == 0) ||
108       (strcmp (buf, "Y\n") == 0))
109     return TRUE;
110
111   return FALSE;
112 }
113
114 static void
115 debug (char *progname,
116        int   method)
117 {
118   pid_t pid;
119   char buf[16];
120   char *args[4] = { "gdb", NULL, NULL, NULL };
121   volatile int x;
122
123   sprintf (buf, "%d", (int) getpid ());
124
125   args[1] = progname;
126   args[2] = buf;
127
128   switch (method)
129     {
130     case INTERACTIVE:
131       fprintf (stdout, "pid: %s\n", buf);
132       break;
133     case STACK_TRACE:
134       pid = fork ();
135       if (pid == 0)
136         {
137           stack_trace (args);
138           _exit (0);
139         }
140       else if (pid == (pid_t) -1)
141         {
142           perror ("could not fork");
143           return;
144         }
145       break;
146     }
147
148   x = 1;
149   while (x)
150     ;
151 }
152
153 static void
154 stack_trace (char **args)
155 {
156   pid_t pid;
157   int in_fd[2];
158   int out_fd[2];
159   SELECT_MASK fdset;
160   SELECT_MASK readset;
161   struct timeval tv;
162   int sel, index, state;
163   char buffer[256];
164   char c;
165
166   stack_trace_done = 0;
167   signal (SIGCHLD, stack_trace_sigchld);
168
169   if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
170     {
171       perror ("could open pipe");
172       _exit (0);
173     }
174
175   pid = fork ();
176   if (pid == 0)
177     {
178       close (0); dup (in_fd[0]);   /* set the stdin to the in pipe */
179       close (1); dup (out_fd[1]);  /* set the stdout to the out pipe */
180       close (2); dup (out_fd[1]);  /* set the stderr to the out pipe */
181
182       execvp (args[0], args);      /* exec gdb */
183       perror ("exec failed");
184       _exit (0);
185     }
186   else if (pid == (pid_t) -1)
187     {
188       perror ("could not fork");
189       _exit (0);
190     }
191
192   FD_ZERO (&fdset);
193   FD_SET (out_fd[0], &fdset);
194
195   write (in_fd[1], "backtrace\n", 10);
196   write (in_fd[1], "p x = 0\n", 8);
197   write (in_fd[1], "quit\n", 5);
198
199   index = 0;
200   state = 0;
201
202   while (1)
203     {
204       readset = fdset;
205       tv.tv_sec = 1;
206       tv.tv_usec = 0;
207
208       sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
209       if (sel == -1)
210         break;
211
212       if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
213         {
214           if (read (out_fd[0], &c, 1))
215             {
216               switch (state)
217                 {
218                 case 0:
219                   if (c == '#')
220                     {
221                       state = 1;
222                       index = 0;
223                       buffer[index++] = c;
224                     }
225                   break;
226                 case 1:
227                   buffer[index++] = c;
228                   if ((c == '\n') || (c == '\r'))
229                     {
230                       buffer[index] = 0;
231                       fprintf (stdout, "%s", buffer);
232                       state = 0;
233                       index = 0;
234                     }
235                   break;
236                 default:
237                   break;
238                 }
239             }
240         }
241       else if (stack_trace_done)
242         break;
243     }
244
245   close (in_fd[0]);
246   close (in_fd[1]);
247   close (out_fd[0]);
248   close (out_fd[1]);
249   _exit (0);
250 }
251
252 static void
253 stack_trace_sigchld (int signum)
254 {
255   stack_trace_done = 1;
256 }