Updated Bosnian translation
[bug-buddy.git] / segv_handler / gnome-segvhanlder.c
blobae3196efeb8bc330d44eca6ab6fbc2b1752b3c84
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>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <sys/wait.h>
28 #include <glib.h>
29 #include <glib/gstdio.h>
31 #include <gdk/gdk.h>
32 #include <gdk/gdkx.h>
33 #include <X11/Xlib.h>
35 #include <config.h>
37 #include <string.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;
47 typedef struct {
48 int start;
49 int next_free;
50 int size;
51 char **strings;
52 } CircBuff;
54 static CircBuff * log_buff = NULL;
55 #define LOG_BUFFER_SIZE 15
57 static void
58 circ_buff_free (CircBuff *buff)
60 if (!buff) {
61 return;
64 g_strfreev (buff->strings);
65 g_free (buff);
67 buff = NULL;
70 static CircBuff *
71 circ_buff_new (int size)
73 CircBuff *retval;
75 retval = g_new0 (CircBuff, 1);
76 retval->strings = g_new0 (char *, size + 1);
77 retval->strings[size] = NULL;
78 retval->size = size;
80 return retval;
83 static void
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;
95 static char *
96 circ_buff_to_file (CircBuff *buff)
98 int tmp_fd, i;
99 char *actual_name = NULL;
100 GError *error = NULL;
101 const char *header;
103 if (!buff) {
104 return NULL;
107 tmp_fd = g_file_open_tmp ("bug-buddy-XXXXXX", &actual_name, &error);
109 if (error) {
110 g_warning ("Unable to create the warnings temp file: %s", error->message);
111 g_error_free (error);
112 return NULL;
115 header = "\n\n---- Critical and fatal warnings logged during execution ----\n\n";
116 write (tmp_fd, header, strlen (header));
118 i = buff->start;
120 while (buff->strings[i] != NULL) {
121 /* write to file */
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)
128 break;
131 close (tmp_fd);
133 return actual_name;
136 static void
137 bug_buddy_log_handler (const gchar *log_domain,
138 GLogLevelFlags log_level,
139 const gchar *message,
140 gpointer user_data)
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).
145 if (old_handler) {
146 old_handler (log_domain, log_level, message, user_data);
147 } else {
148 g_log_default_handler (log_domain, log_level, message, user_data);
151 if (log_level &
152 (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL))
154 /* log the message into memory */
155 if (!log_buff) {
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));
166 static void
167 bugbuddy_segv_handle(int signum)
169 static int in_segv = 0;
170 struct sigaction sa;
171 pid_t pid;
172 gchar *appname;
173 gboolean res;
175 sa.sa_handler = NULL;
176 in_segv++;
178 if (in_segv > 2) {
179 /* The fprintf() was segfaulting, we are just totally hosed */
180 _exit(1);
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");
184 _exit(1);
187 release_grabs ();
189 appname = g_get_prgname ();
190 pid = getpid ();
191 res = run_bug_buddy (appname, pid);
192 if (!res)
193 _exit (1);
195 _exit(0);
198 static gboolean
199 release_grabs (void)
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 ());
210 gdk_flush();
212 return TRUE;
215 static gboolean
216 run_bug_buddy (const gchar *appname, pid_t pid)
218 gboolean res;
219 char *warning_file, *exec_str;
220 GString *args_str;
221 GError *error = NULL;
223 if (pid == 0)
224 return FALSE;
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);
232 if (warning_file) {
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,
241 NULL, &error);
242 g_free (exec_str);
243 if (!res) {
244 g_warning ("Couldn't run bug-buddy\n");
245 return FALSE;
248 return TRUE;
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;
260 struct sigaction sa;
261 memset(&sa, 0, sizeof(sa));
262 setptr = &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) {
292 old_handler = NULL;
295 return 0;
298 const char *
299 g_module_check_init (GModule *module)
301 g_module_make_resident (module);
303 return NULL;