removed dummy structure definitions for struct _GCache, _GTree, _GTimer,
[platform/upstream/glib.git] / 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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <signal.h>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include "glib.h"
24 #ifdef HAVE_SYS_TIME_H
25 #include <sys/time.h>
26 #endif
27 #ifdef HAVE_SYS_TIMES_H
28 #include <sys/times.h>
29 #endif
30 #include <sys/types.h>
31
32 #include <time.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifdef HAVE_SYS_SELECT_H
38 #include <sys/select.h>
39 #endif /* HAVE_SYS_SELECT_H */
40
41 #ifdef STDC_HEADERS
42 #include <string.h> /* for bzero on BSD systems */
43 #endif
44
45 #ifdef _MSC_VER
46 #include <process.h>            /* For _getpid() */
47 #endif
48
49 #ifndef NO_FD_SET
50 #  define SELECT_MASK fd_set
51 #else
52 #  ifndef _AIX
53      typedef long fd_mask;
54 #  endif
55 #  if defined(_IBMR2)
56 #    define SELECT_MASK void
57 #  else
58 #    define SELECT_MASK int
59 #  endif
60 #endif
61
62
63 static void stack_trace (char **args);
64
65 extern volatile gboolean glib_on_error_halt;
66 volatile gboolean glib_on_error_halt = TRUE;
67
68 void
69 g_on_error_query (const gchar *prg_name)
70 {
71   static const gchar *query1 = "[E]xit, [H]alt";
72   static const gchar *query2 = ", show [S]tack trace";
73   static const gchar *query3 = " or [P]roceed";
74   gchar buf[16];
75
76   if (!prg_name)
77     prg_name = g_get_prgname ();
78   
79  retry:
80   
81   if (prg_name)
82     fprintf (stdout,
83              "%s (pid:%u): %s%s%s: ",
84              prg_name,
85              (guint) getpid (),
86              query1,
87              query2,
88              query3);
89   else
90     fprintf (stdout,
91              "(process:%u): %s%s: ",
92              (guint) getpid (),
93              query1,
94              query3);
95   fflush (stdout);
96   
97   fgets (buf, 8, stdin);
98
99   if ((buf[0] == 'E' || buf[0] == 'e')
100       && buf[1] == '\n')
101     _exit (0);
102   else if ((buf[0] == 'P' || buf[0] == 'p')
103            && buf[1] == '\n')
104     return;
105   else if (prg_name
106            && (buf[0] == 'S' || buf[0] == 's')
107            && buf[1] == '\n')
108     {
109       g_on_error_stack_trace (prg_name);
110       goto retry;
111     }
112   else if ((buf[0] == 'H' || buf[0] == 'h')
113            && buf[1] == '\n')
114     {
115       while (glib_on_error_halt)
116         ;
117       glib_on_error_halt = TRUE;
118       return;
119     }
120   else
121     goto retry;
122 }
123
124 void
125 g_on_error_stack_trace (const gchar *prg_name)
126 {
127 #ifndef NATIVE_WIN32
128   pid_t pid;
129   gchar buf[16];
130   gchar *args[4] = { "gdb", NULL, NULL, NULL };
131
132   if (!prg_name)
133     return;
134
135   sprintf (buf, "%u", (guint) getpid ());
136
137   args[1] = (gchar*) prg_name;
138   args[2] = buf;
139
140   pid = fork ();
141   if (pid == 0)
142     {
143       stack_trace (args);
144       _exit (0);
145     }
146   else if (pid == (pid_t) -1)
147     {
148       perror ("unable to fork gdb");
149       return;
150     }
151   
152   while (glib_on_error_halt)
153     ;
154   glib_on_error_halt = TRUE;
155 #else
156   abort ();
157 #endif
158 }
159
160 static gboolean stack_trace_done = FALSE;
161
162 static void
163 stack_trace_sigchld (int signum)
164 {
165   stack_trace_done = TRUE;
166 }
167
168 static void
169 stack_trace (char **args)
170 {
171 #ifndef NATIVE_WIN32
172   pid_t pid;
173   int in_fd[2];
174   int out_fd[2];
175   SELECT_MASK fdset;
176   SELECT_MASK readset;
177   struct timeval tv;
178   int sel, index, state;
179   char buffer[256];
180   char c;
181
182   stack_trace_done = FALSE;
183   signal (SIGCHLD, stack_trace_sigchld);
184
185   if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1))
186     {
187       perror ("unable to open pipe");
188       _exit (0);
189     }
190
191   pid = fork ();
192   if (pid == 0)
193     {
194       close (0); dup (in_fd[0]);   /* set the stdin to the in pipe */
195       close (1); dup (out_fd[1]);  /* set the stdout to the out pipe */
196       close (2); dup (out_fd[1]);  /* set the stderr to the out pipe */
197
198       execvp (args[0], args);      /* exec gdb */
199       perror ("exec failed");
200       _exit (0);
201     }
202   else if (pid == (pid_t) -1)
203     {
204       perror ("unable to fork");
205       _exit (0);
206     }
207
208   FD_ZERO (&fdset);
209   FD_SET (out_fd[0], &fdset);
210
211   write (in_fd[1], "backtrace\n", 10);
212   write (in_fd[1], "p x = 0\n", 8);
213   write (in_fd[1], "quit\n", 5);
214
215   index = 0;
216   state = 0;
217
218   while (1)
219     {
220       readset = fdset;
221       tv.tv_sec = 1;
222       tv.tv_usec = 0;
223
224       sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv);
225       if (sel == -1)
226         break;
227
228       if ((sel > 0) && (FD_ISSET (out_fd[0], &readset)))
229         {
230           if (read (out_fd[0], &c, 1))
231             {
232               switch (state)
233                 {
234                 case 0:
235                   if (c == '#')
236                     {
237                       state = 1;
238                       index = 0;
239                       buffer[index++] = c;
240                     }
241                   break;
242                 case 1:
243                   buffer[index++] = c;
244                   if ((c == '\n') || (c == '\r'))
245                     {
246                       buffer[index] = 0;
247                       fprintf (stdout, "%s", buffer);
248                       state = 0;
249                       index = 0;
250                     }
251                   break;
252                 default:
253                   break;
254                 }
255             }
256         }
257       else if (stack_trace_done)
258         break;
259     }
260
261   close (in_fd[0]);
262   close (in_fd[1]);
263   close (out_fd[0]);
264   close (out_fd[1]);
265   _exit (0);
266 #else
267   abort ();
268 #endif
269 }