ayttm-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Ayttm-commits] CVS: ayttm/src crash.c,NONE,1.1 crash.h,NONE,1.1 Makefil


From: Colin Leroy <address@hidden>
Subject: [Ayttm-commits] CVS: ayttm/src crash.c,NONE,1.1 crash.h,NONE,1.1 Makefile.am,1.6,1.7 main.c,1.7,1.8
Date: Tue, 14 Jan 2003 05:51:58 -0500

Update of /cvsroot/ayttm/ayttm/src
In directory subversions:/tmp/cvs-serv28044/src

Modified Files:
        Makefile.am main.c 
Added Files:
        crash.c crash.h 
Log Message:
 Add crash handler (./configure --enable-crash-handler)


--- NEW FILE: crash.c ---
/*
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
 * Copyright (C) 2002 by the Sylpheed Claws Team and Hiroyuki Yamamoto
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
 * Many thanks to Alfons Hoogervorst for having written this (for Sylpheed
 * Claws originally) !
 *
 */
#ifdef HAVE_CONFIG_H
#       include <config.h>
#endif

#ifdef CRASH_DIALOG

#include <glib.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <errno.h>
#include <fcntl.h>

#if HAVE_SYS_UTSNAME_H
#       include <sys/utsname.h>
#endif

#if defined(__GNU_LIBRARY__)
#       include <gnu/libc-version.h>
#endif

#include "intl.h"
#include "crash.h"
#include "globals.h"
#include "browser.h"

/*
 * NOTE: the crash dialog is called when sylpheed is not 
 * initialized, so do not assume settings are available.
 * for example, loading / creating pixmaps seems not 
 * to be possible.
 */

/***/

static GtkWidget        *crash_dialog_show              (const gchar *text, 
                                                         const gchar 
*debug_output);
static void              crash_create_debugger_file     (void);
static void              crash_save_crash_log           (GtkButton *, const 
gchar *);
static void              crash_create_bug_report        (GtkButton *, const 
gchar *);
static void              crash_debug                    (unsigned long 
crash_pid, 
                                                         gchar   *exe_image,
                                                         GString *debug_output);
static const gchar      *get_compiled_in_features       (void);
static const gchar      *get_lib_version                (void);
static const gchar      *get_operating_system           (void);
static gboolean          is_crash_dialog_allowed        (void);
static void              crash_handler                  (int sig);
static void              crash_cleanup_exit             (void);

/***/

static const gchar *DEBUG_SCRIPT = "bt\nkill\nq";

/***/

/*!
 *\brief        install crash handlers
 */
void crash_install_handlers(void)
{
#if CRASH_DIALOG 
        sigset_t mask;

        if (!is_crash_dialog_allowed()) return;

        sigemptyset(&mask);

#ifdef SIGSEGV
        signal(SIGSEGV, crash_handler);
        sigaddset(&mask, SIGSEGV);
#endif
        
#ifdef SIGFPE
        signal(SIGFPE, crash_handler);
        sigaddset(&mask, SIGFPE);
#endif

#ifdef SIGILL
        signal(SIGILL, crash_handler);
        sigaddset(&mask, SIGILL);
#endif

#ifdef SIGABRT
        signal(SIGABRT, crash_handler);
        sigaddset(&mask, SIGABRT);
#endif

#ifdef SIGTERM
        signal(SIGTERM, crash_handler);
        sigaddset(&mask, SIGTERM);
#endif

        sigprocmask(SIG_UNBLOCK, &mask, 0);
#endif /* CRASH_DIALOG */       
}

/***/

/*!
 *\brief        crash dialog entry point 
 */
void crash_main(const char *arg) 
{
#if CRASH_DIALOG 
        gchar *text;
        gchar **tokens;
        unsigned long pid;
        GString *output;

        crash_create_debugger_file();
        tokens = g_strsplit(arg, ",", 0);

        pid = atol(tokens[0]);
        text = g_strdup_printf(_("Yattm process (%ld) received signal %ld"),
                               pid, atol(tokens[1]));

        output = g_string_new("");     
        crash_debug(pid, tokens[2], output);

        crash_dialog_show(text, output->str);
        g_string_free(output, TRUE);
        g_free(text);
        g_strfreev(tokens);
#endif /* CRASH_DIALOG */       
}

/*!
 *\brief        show crash dialog
 *
 *\param        text Description
 *\param        debug_output Output text by gdb
 *
 *\return       GtkWidget * Dialog widget
 */
static GtkWidget *crash_dialog_show(const gchar *text, const gchar 
*debug_output)
{
        GtkWidget *window1;
        GtkWidget *vbox1;
        GtkWidget *hbox1;
        GtkWidget *label1;
        GtkWidget *frame1;
        GtkWidget *scrolledwindow1;
        GtkWidget *text1;
        GtkWidget *hbuttonbox3;
        GtkWidget *hbuttonbox4;
        GtkWidget *button3;
        GtkWidget *button4;
        GtkWidget *button5;
        gchar     *crash_report;

        window1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_container_set_border_width(GTK_CONTAINER(window1), 5);
        gtk_window_set_title(GTK_WINDOW(window1), _("Yattm has crashed"));
        gtk_window_set_position(GTK_WINDOW(window1), GTK_WIN_POS_CENTER);
        gtk_window_set_modal(GTK_WINDOW(window1), TRUE);
        gtk_window_set_default_size(GTK_WINDOW(window1), 460, 272);


        vbox1 = gtk_vbox_new(FALSE, 2);
        gtk_widget_show(vbox1);
        gtk_container_add(GTK_CONTAINER(window1), vbox1);

        hbox1 = gtk_hbox_new(FALSE, 4);
        gtk_widget_show(hbox1);
        gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
        gtk_container_set_border_width(GTK_CONTAINER(hbox1), 4);

        label1 = gtk_label_new
            (g_strdup_printf(_("%s.\nPlease file a bug report and include the 
information below."), text));
        gtk_widget_show(label1);
        gtk_box_pack_start(GTK_BOX(hbox1), label1, TRUE, TRUE, 0);
        gtk_misc_set_alignment(GTK_MISC(label1), 7.45058e-09, 0.5);

        frame1 = gtk_frame_new(_("Debug log"));
        gtk_widget_show(frame1);
        gtk_box_pack_start(GTK_BOX(vbox1), frame1, TRUE, TRUE, 0);

        scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
        gtk_widget_show(scrolledwindow1);
        gtk_container_add(GTK_CONTAINER(frame1), scrolledwindow1);
        gtk_container_set_border_width(GTK_CONTAINER(scrolledwindow1), 3);
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow1),
                                       GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);

        text1 = gtk_text_new(NULL, NULL);
        gtk_text_set_editable(GTK_TEXT(text1), FALSE);
        gtk_widget_show(text1);
        gtk_container_add(GTK_CONTAINER(scrolledwindow1), text1);
        
        crash_report = g_strdup_printf(
                "Yattm version %s\nGTK+ version 
%d.%d.%d\nFeatures:%s\nOperating system: %s\nC Library: %s\n--\n%s",
                VERSION,
                gtk_major_version, gtk_minor_version, gtk_micro_version,
                get_compiled_in_features(),
                get_operating_system(),
                get_lib_version(),
                debug_output);

        gtk_text_insert(GTK_TEXT(text1), NULL, NULL, NULL, crash_report, -1);

        hbuttonbox3 = gtk_hbutton_box_new();
        gtk_widget_show(hbuttonbox3);
        gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox3, FALSE, FALSE, 0);

        hbuttonbox4 = gtk_hbutton_box_new();
        gtk_widget_show(hbuttonbox4);
        gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox4, FALSE, FALSE, 0);

        button3 = gtk_button_new_with_label(_("Close"));
        gtk_widget_show(button3);
        gtk_container_add(GTK_CONTAINER(hbuttonbox4), button3);
        GTK_WIDGET_SET_FLAGS(button3, GTK_CAN_DEFAULT);

        button4 = gtk_button_new_with_label(_("Save"));
        gtk_widget_show(button4);
        gtk_container_add(GTK_CONTAINER(hbuttonbox4), button4);
        GTK_WIDGET_SET_FLAGS(button4, GTK_CAN_DEFAULT);

        button5 = gtk_button_new_with_label(_("Create bug report"));
        gtk_widget_show(button5);
        gtk_container_add(GTK_CONTAINER(hbuttonbox4), button5);
        GTK_WIDGET_SET_FLAGS(button5, GTK_CAN_DEFAULT);
        
        gtk_signal_connect(GTK_OBJECT(window1), "delete_event",
                           GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
        gtk_signal_connect(GTK_OBJECT(button3),   "clicked",
                           GTK_SIGNAL_FUNC(gtk_main_quit), NULL);
        gtk_signal_connect(GTK_OBJECT(button4), "clicked",
                           GTK_SIGNAL_FUNC(crash_save_crash_log),
                           crash_report);
        gtk_signal_connect(GTK_OBJECT(button5), "clicked",
                           GTK_SIGNAL_FUNC(crash_create_bug_report),
                           NULL);

        gtk_widget_show(window1);

        gtk_main();
        return window1;
}

static int str_write_to_file(const gchar *str, const gchar *file)
{
        FILE *fp;
        size_t len;

        g_return_val_if_fail(str != NULL, -1);
        g_return_val_if_fail(file != NULL, -1);

        if ((fp = fopen(file, "wb")) == NULL) {
                perror("fopen");
                return -1;
        }

        len = strlen(str);
        if (len == 0) {
                fclose(fp);
                return 0;
        }

        if (fwrite(str, len, 1, fp) != 1) {
                perror("fwrite");
                fclose(fp);
                unlink(file);
                return -1;
        }

        if (fclose(fp) == EOF) {
                perror("fclose");
                unlink(file);
                return -1;
        }

        return 0;
}


/*!
 *\brief        create debugger script file in sylpheed directory.
 *              all the other options (creating temp files) looked too 
 *              convoluted.
 */
static void crash_create_debugger_file(void)
{
        gchar *filespec = g_strconcat(config_dir, G_DIR_SEPARATOR_S, 
DEBUGGERRC, NULL);
        
        str_write_to_file(DEBUG_SCRIPT, filespec);
        g_free(filespec);
}

static void crash_save_crash_log(GtkButton *button, const gchar *text)
{
        time_t timer;
        struct tm *lt;
        char buf[100];
        gchar *filename;

        timer = time(NULL);
        lt = localtime(&timer);
        strftime(buf, sizeof buf, "yattm-crash-log-%Y-%m-%d-%H-%M-%S.txt", lt);
        printf("saving crash log to %s\n",buf);
        str_write_to_file(text, buf);
        g_free(filename);       
}

/*!
 *\brief        create bug report (goes to Sylpheed Claws bug tracker)  
 */
static void crash_create_bug_report(GtkButton *button, const gchar *data)
{
        
open_url_nw(NULL,"http://savannah.nongnu.org/bugs/?func=addbug&group=ayttm";);
}

/*!
 *\brief        launches debugger and attaches it to crashed sylpheed
 */
static void crash_debug(unsigned long crash_pid, 
                        gchar *exe_image,
                        GString *debug_output)
{
        int choutput[2];
        pid_t pid;

        pipe(choutput);

        if (0 == (pid = fork())) {
                char *argp[10];
                char **argptr = argp;
                gchar *filespec = g_strconcat(config_dir, G_DIR_SEPARATOR_S, 
DEBUGGERRC, NULL);

                setgid(getgid());
                setuid(getuid());

                /*
                 * setup debugger to attach to crashed sylpheed
                 */
                *argptr++ = "gdb"; 
                *argptr++ = "--nw";
                *argptr++ = "--nx";
                *argptr++ = "--quiet";
                *argptr++ = "--batch";
                *argptr++ = "-x";
                *argptr++ = filespec;
                *argptr++ = exe_image;
                *argptr++ = g_strdup_printf("%ld", crash_pid);
                *argptr   = NULL;

                /*
                 * redirect output to write end of pipe
                 */
                close(1);
                dup(choutput[1]);
                close(choutput[0]);
                if (-1 == execvp("gdb", argp)) 
                        puts("error execvp\n");
        } else {
                char buf[100];
                int r;
        
                waitpid(pid, NULL, 0);

                /*
                 * make it non blocking
                 */
                if (-1 == fcntl(choutput[0], F_SETFL, O_NONBLOCK))
                        puts("set to non blocking failed\n");

                /*
                 * get the output
                 */
                do {
                        r = read(choutput[0], buf, sizeof buf - 1);
                        if (r > 0) {
                                buf[r] = 0;
                                g_string_append(debug_output, buf);
                        }
                } while (r > 0);
                
                close(choutput[0]);
                close(choutput[1]);
                
                /*
                 * kill the process we attached to
                 */
                kill(crash_pid, SIGCONT); 
        }
}

/***/

/*!
 *\brief        features
 */
static const gchar *get_compiled_in_features(void)
{
        return g_strdup_printf("%s",
#ifdef HAVE_ICONV
                   " iconv"
#endif
#ifdef HAVE_ISPELL
                   " ispell"
#endif
#ifdef HAVE_LIBXFT
                   " Xft"
#endif
        "");
}

/***/

/*!
 *\brief        library version
 */
static const gchar *get_lib_version(void)
{
#if defined(__GNU_LIBRARY__)
        return g_strdup_printf("GNU libc %s", gnu_get_libc_version());
#else
        return g_strdup(_("Unknown"));
#endif
}

/***/

/*!
 *\brief        operating system
 */
static const gchar *get_operating_system(void)
{
#if HAVE_SYS_UTSNAME_H
        struct utsname utsbuf;
        uname(&utsbuf);
        return g_strdup_printf("%s %s (%s)",
                               utsbuf.sysname,
                               utsbuf.release,
                               utsbuf.machine);
#else
        return g_strdup(_("Unknown"));
        
#endif
}

/***/

/*!
 *\brief        see if the crash dialog is allowed (because some
 *              developers may prefer to run sylpheed under gdb...)
 */
static gboolean is_crash_dialog_allowed(void)
{
        return !getenv("YATTM_NO_CRASH");
}

/*!
 *\brief        this handler will probably evolve into 
 *              something better.
 */
static void crash_handler(int sig)
{
        pid_t pid;
        static volatile unsigned long crashed_ = 0;

        /*
         * let's hope startup_dir and argv0 aren't trashed.
         * both are defined in main.c.
         */
        extern gchar *startup_dir;
        extern gchar *argv0;


        /*
         * besides guarding entrancy it's probably also better 
         * to mask off signals
         */
        if (crashed_) return;

        crashed_++;

#ifdef SIGTERM
        if (sig == SIGTERM) 
                exit(1);
#endif

        /*
         * gnome ungrabs focus, and flushes gdk. mmmh, good idea.
         */
        gdk_pointer_ungrab(GDK_CURRENT_TIME);
        gdk_keyboard_ungrab(GDK_CURRENT_TIME);
        gdk_flush();

        if (0 == (pid = fork())) {
                char buf[50];
                char *args[4];
        
                /*
                 * probably also some other parameters (like GTK+ ones).
                 * also we pass the full startup dir and the real command
                 * line typed in (argv0)
                 */
                args[0] = argv0; 
                args[1] = "--crash";
                sprintf(buf, "%d,%d,%s", getppid(), sig, argv0);
                args[2] = buf;
                args[3] = NULL;

                chdir(startup_dir);
                setgid(getgid());
                setuid(getuid());
                execvp(argv0, args);
        } else {
                waitpid(pid, NULL, 0);
                crash_cleanup_exit();
                _exit(253);
        }

        _exit(253);
}

/*!
 *\brief        put all the things here we can do before
 *              letting the program die
 */
static void crash_cleanup_exit(void)
{
        char *filename = g_strdup_printf("%s%s%s", config_dir, 
G_DIR_SEPARATOR,"eb_socket");
        unlink(filename);
        g_free(filename);
}

#endif

--- NEW FILE: crash.h ---
/*
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
 * Copyright (C) 2002 by the Sylpheed Claws Team and  Hiroyuki Yamamoto
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef CRASH_H__
#define CRASH_H__

#define DEBUGGERRC      "debuggerrc"

void             crash_install_handlers (void);
void             crash_main             (const char *arg); 

#endif /* CRASH_H__ */
 

Index: Makefile.am
===================================================================
RCS file: /cvsroot/ayttm/ayttm/src/Makefile.am,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Makefile.am 5 Jan 2003 08:32:16 -0000       1.6
+++ Makefile.am 14 Jan 2003 10:51:56 -0000      1.7
@@ -7,17 +7,17 @@
        chat_room.c value_pair.c edit_group_window.c log_window.c gtkspell.c \
        trigger.c console_session.c gtk_eb_html.c input_list.c nomodule.c \
        plugin_api.c plugin.c file_select.c extgtktext.c contact_actions.c \
-       smileys.c help_menu.c account_parser.y account_scanner.l \
+       smileys.c help_menu.c crash.c account_parser.y account_scanner.l \
        contact_parser.y contact_scanner.l
 
-noinst_HEADERS = account.h service.h contact.h gtk_globals.h globals.h 
status.h \
-       info_window.h chat_window.h util.h add_contact_window.h sound.h \
-       about.h dialog.h prefs.h progress_window.h away_window.h 
message_parse.h help_menu.h \
-       chat_room.h value_pair.h log_window.h info_window.h log_window.h \
-       gtkspell.h trigger.h console_session.h \
+noinst_HEADERS = account.h service.h contact.h gtk_globals.h globals.h \
+       status.h info_window.h chat_window.h util.h add_contact_window.h \
+       sound.h about.h dialog.h prefs.h progress_window.h away_window.h \
+       message_parse.h help_menu.h chat_room.h value_pair.h log_window.h \
+       info_window.h log_window.h gtkspell.h trigger.h console_session.h \
        gtk_eb_html.h browser.h input_list.h plugin.h plugin_api.h debug.h \
        nomodule.h file_select.h extgtktext.h contact_actions.h \
-       smileys.h intl.h account_parser.h contact_parser.h
+       smileys.h intl.h account_parser.h contact_parser.h crash.h
 
 EXTRA_DIST =
 
@@ -53,7 +53,7 @@
        @echo \#define MODULE_DIR \"${datadir}/yattm/modules\" >> defaults.h;
        @echo "#endif" >> defaults.h;
        @echo "#endif" >> defaults.h;
-       @touch main.c status.c about.c
+       @touch main.c status.c about.c crash.c
 
 account_parser.c: account_parser.y
        $(YACC) $(AM_LFLAGS) $(LFLAGS) -d -p account $< && \

Index: main.c
===================================================================
RCS file: /cvsroot/ayttm/ayttm/src/main.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- main.c      10 Jan 2003 23:43:56 -0000      1.7
+++ main.c      14 Jan 2003 10:51:56 -0000      1.8
@@ -56,11 +56,18 @@
 #include "libproxy/libproxy.h"
 #include "console_session.h"
 #include "prefs.h"
+#include "crash.h"
 
 #include <locale.h>
 
 #define PACKAGE "yattm"
 
+#ifdef CRASH_DIALOG
+gchar *startup_dir;
+gchar *argv0;
+int crash;
+gchar *crash_param;
+#endif
 
 static void eb_cli_ver ()
 {
@@ -140,7 +147,7 @@
 }
 
 
-/* Global variable, referenced in gtk_globals.h */
+/* Global variable, referenced in globals.h */
 char config_dir[1024] = "";
 GtkWidget *current_parent_widget = NULL;
 
@@ -210,6 +217,9 @@
                {"contact", required_argument, NULL, 'c'},
                {"message", required_argument, NULL, 'm'},
                {"config-dir", required_argument, NULL, 'd'},
+#ifdef CRASH_DIALOG
+               {"crash", required_argument, NULL, 'C'},
+#endif
                {0, 0, 0, 0}
                };
     
@@ -227,7 +237,6 @@
                        break;
                }
 
-
                switch (c) 
                {
                    case 'v':           /* version information */
@@ -267,6 +276,12 @@
                        strcpy(message, optarg);
                        break;
 
+#ifdef CRASH_DIALOG
+                   case 'C':
+                       crash = 1;    
+                       crash_param = strdup(optarg);
+                       break;
+#endif                 
                    case 'd':
                        strcpy(config_dir, optarg);
                        /*Make sure we have directory delimiter */
@@ -291,6 +306,19 @@
 
                }
     } 
+    
+#ifdef CRASH_DIALOG
+    startup_dir = g_get_current_dir();
+    argv0 = g_strdup(argv[0]);
+    if (crash) {
+           gtk_set_locale();
+           gtk_init(&argc, &argv);
+           eb_read_prefs();
+           crash_main(crash_param);
+           return 0;
+    }
+    crash_install_handlers();
+#endif
 
 #endif
 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]