1 /* bug-buddy bug submitting program
3 * Copyright (C) 2007 Fernando Herrera
5 * Authors: Fernando Herrera <fherrera@onirica.com>
6 * Cosimo Cecchi <cosimoc@gnome.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22 #include <sys/types.h>
29 #include <glib/gstdio.h>
39 const char *g_module_check_init (GModule
*module
);
40 int gtk_module_init (int *argc
, char** argv
[]);
41 static gboolean
run_bug_buddy (const gchar
*appname
, pid_t pid
);
42 static gboolean
release_grabs (void);
44 static gchar
*bugbuddy
;
45 static GLogFunc old_handler
= NULL
;
54 static CircBuff
* log_buff
= NULL
;
55 #define LOG_BUFFER_SIZE 15
58 circ_buff_free (CircBuff
*buff
)
64 g_strfreev (buff
->strings
);
71 circ_buff_new (int size
)
75 retval
= g_new0 (CircBuff
, 1);
76 retval
->strings
= g_new0 (char *, size
+ 1);
77 retval
->strings
[size
] = NULL
;
84 circ_add (CircBuff
*buff
, char * str
)
86 if (buff
->strings
[buff
->next_free
]) {
87 g_free (buff
->strings
[buff
->next_free
]);
88 buff
->start
= (buff
->start
+ 1) % buff
->size
;
91 buff
->strings
[buff
->next_free
] = str
;
92 buff
->next_free
= (buff
->next_free
+ 1) % buff
->size
;
96 circ_buff_to_file (CircBuff
*buff
)
99 char *actual_name
= NULL
;
100 GError
*error
= NULL
;
107 tmp_fd
= g_file_open_tmp ("bug-buddy-XXXXXX", &actual_name
, &error
);
110 g_warning ("Unable to create the warnings temp file: %s", error
->message
);
111 g_error_free (error
);
115 header
= "\n\n---- Critical and fatal warnings logged during execution ----\n\n";
116 write (tmp_fd
, header
, strlen (header
));
120 while (buff
->strings
[i
] != NULL
) {
122 write (tmp_fd
, buff
->strings
[i
], strlen (buff
->strings
[i
]));
124 /* increase and check for overflow */
125 i
= (i
+ 1) % buff
->size
;
127 if (i
== buff
->start
)
137 bug_buddy_log_handler (const gchar
*log_domain
,
138 GLogLevelFlags log_level
,
139 const gchar
*message
,
142 /* forward the message to the real handler and use the default GLib
143 * handler if that's NULL (should never happen, but who knows).
146 old_handler (log_domain
, log_level
, message
, user_data
);
148 g_log_default_handler (log_domain
, log_level
, message
, user_data
);
152 (G_LOG_LEVEL_ERROR
| G_LOG_LEVEL_CRITICAL
| G_LOG_FLAG_FATAL
))
154 /* log the message into memory */
156 log_buff
= circ_buff_new (LOG_BUFFER_SIZE
);
159 /* if the log domain is NULL, assume it's a message coming from the app,
160 * see the docs for G_LOG_DOMAIN.
162 circ_add (log_buff
, g_strdup_printf ("** %s **: %s \n", log_domain
? log_domain
: g_get_prgname (), message
));
167 bugbuddy_segv_handle(int signum
)
169 static int in_segv
= 0;
175 sa
.sa_handler
= NULL
;
179 /* The fprintf() was segfaulting, we are just totally hosed */
181 } else if (in_segv
> 1) {
182 /* dialog display isn't working out */
183 fprintf(stderr
, "Multiple segmentation faults occurred; can't display error dialog\n");
189 appname
= g_get_prgname ();
191 res
= run_bug_buddy (appname
, pid
);
201 /* Make sure we release grabs */
202 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
203 gdk_keyboard_ungrab(GDK_CURRENT_TIME
);
205 /* TODO: can we replace this with gdk_x11_ungrab_server ()?
206 * see http://bugzilla.gnome.org/show_bug.cgi?id=550135.
208 XUngrabServer (GDK_DISPLAY ());
216 run_bug_buddy (const gchar
*appname
, pid_t pid
)
219 char *warning_file
, *exec_str
;
221 GError
*error
= NULL
;
226 warning_file
= circ_buff_to_file (log_buff
);
227 circ_buff_free (log_buff
);
229 args_str
= g_string_new ("bug-buddy ");
230 g_string_append_printf (args_str
, "--appname=\"%s\" ", appname
);
233 g_string_append_printf (args_str
, "--include=\"%s\" --unlink-tempfile ", warning_file
);
234 g_free (warning_file
);
237 g_string_append_printf (args_str
, "--pid=%d",(int) pid
);
239 exec_str
= g_string_free (args_str
, FALSE
);
240 res
= g_spawn_command_line_sync (exec_str
, NULL
, NULL
,
244 g_warning ("Couldn't run bug-buddy\n");
252 gtk_module_init (int *argc
, char** argv
[])
254 bugbuddy
= g_find_program_in_path ("bug-buddy");
256 if (bugbuddy
&& !g_getenv ("GNOME_DISABLE_CRASH_DIALOG")) {
258 static struct sigaction
*setptr
;
259 static struct sigaction old_action
;
261 memset(&sa
, 0, sizeof(sa
));
264 sa
.sa_handler
= bugbuddy_segv_handle
;
266 sigaction(SIGSEGV
, NULL
, &old_action
);
267 if (old_action
.sa_handler
== SIG_DFL
)
268 sigaction(SIGSEGV
, setptr
, NULL
);
270 sigaction(SIGABRT
, NULL
, &old_action
);
271 if (old_action
.sa_handler
== SIG_DFL
)
272 sigaction(SIGABRT
, setptr
, NULL
);
274 sigaction(SIGTRAP
, NULL
, &old_action
);
275 if (old_action
.sa_handler
== SIG_DFL
)
276 sigaction(SIGTRAP
, setptr
, NULL
);
278 sigaction(SIGFPE
, NULL
, &old_action
);
279 if (old_action
.sa_handler
== SIG_DFL
)
280 sigaction(SIGFPE
, setptr
, NULL
);
282 sigaction(SIGBUS
, NULL
, &old_action
);
283 if (old_action
.sa_handler
== SIG_DFL
)
284 sigaction(SIGBUS
, setptr
, NULL
);
286 old_handler
= g_log_set_default_handler (bug_buddy_log_handler
, NULL
);
288 /* We cannot call previous log handlers other than glib's default
289 * because we don't know its previous user_data and they may rely on it
290 * See https://bugzilla.gnome.org/show_bug.cgi?id=622068 */
291 if (old_handler
!= g_log_default_handler
) {
299 g_module_check_init (GModule
*module
)
301 g_module_make_resident (module
);