/** * * Beryl crash handler plugin * * crashhandler.c * * Copyright : (C) 2006 by Dennis Kasprzyk * E-mail : onestone@beryl-project.org * * * 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. * **/ #include #include #include #include #include #include #define GET_CRASHHANDLER_DISPLAY(d) \ ((CrashhandlerDisplay *) (d)->privates[displayPrivateIndex].ptr) #define CRASHHANDLER_DISPLAY(d) \ CrashhandlerDisplay *cd = GET_CRASHHANDLER_DISPLAY (d) #define CRASHHANDLER_DISPLAY_OPTION_ENABLED 0 #define CRASHHANDLER_DISPLAY_OPTION_START_WM 1 #define CRASHHANDLER_DISPLAY_OPTION_WM 2 #define CRASHHANDLER_DISPLAY_OPTION_NUM 3 #define CRASHHANDLER_DISPLAY_OPTION_ENABLED_DEFAULT TRUE #define CRASHHANDLER_DISPLAY_OPTION_START_WM_DEFAULT FALSE #define CRASHHANDLER_DISPLAY_OPTION_WM_DEFAULT "" #define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption)) static int displayPrivateIndex = 0; static CompDisplay *cDisplay; typedef struct _CrashhandlerDisplay { int screenPrivateIndex; CompOption opt[CRASHHANDLER_DISPLAY_OPTION_NUM]; } CrashhandlerDisplay; static void crash_handler(int sig) { if (sig == SIGSEGV || sig == SIGFPE || sig == SIGILL || sig == SIGABRT) { CRASHHANDLER_DISPLAY(cDisplay); static int count = 0; if (++count > 1) exit(1); // backtrace char cmd[1024]; sprintf(cmd, "echo -e \"set prompt\nthread apply all bt full\necho \\\\\\n\necho \\\\\\n\nbt\nquit\" > /tmp/gdb.tmp; gdb -q %s %i < /tmp/gdb.tmp | grep -v \"No symbol table\" | tee /tmp/beryl_crash-%i.out; rm -f /tmp/gdb.tmp; echo \"\n[CRASH_HANDLER]: \\\"/tmp/beryl_crash-%i.out\\\" created!\n\"", getProgramName(), getpid(), getpid(), getpid()); system(cmd); if (cd->opt[CRASHHANDLER_DISPLAY_OPTION_START_WM].value.b) { if (fork() == 0) { setsid(); putenv(cDisplay->displayString); execl("/bin/sh", "/bin/sh", "-c", cd->opt[CRASHHANDLER_DISPLAY_OPTION_WM].value.s, NULL); exit(0); } } exit(1); } } static Bool crashhandlerSetDisplayOption(CompDisplay * display, char *name, CompOptionValue * value) { CompOption *o; int index; CRASHHANDLER_DISPLAY(display); o = compFindOption(cd->opt, NUM_OPTIONS(cd), name, &index); if (!o) return FALSE; switch (index) { case CRASHHANDLER_DISPLAY_OPTION_ENABLED: if (compSetBoolOption(o, value)) { if (value->b) { // enable crash handler signal(SIGSEGV, crash_handler); signal(SIGFPE, crash_handler); signal(SIGILL, crash_handler); signal(SIGABRT, crash_handler); } else { // disable crash handler signal(SIGSEGV, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGILL, SIG_DFL); signal(SIGABRT, SIG_DFL); } return TRUE; } break; case CRASHHANDLER_DISPLAY_OPTION_START_WM: if (compSetBoolOption(o, value)) return TRUE; break; case CRASHHANDLER_DISPLAY_OPTION_WM: if (compSetStringOption(o, value)) return TRUE; break; default: break; } return FALSE; } static void crashhandlerDisplayInitOptions(CrashhandlerDisplay * cd) { CompOption *o; o = &cd->opt[CRASHHANDLER_DISPLAY_OPTION_ENABLED]; o->advanced = False; o->name = "enabled"; o->group = N_("Misc. settings"); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Enable Crash Handler"); o->longDesc = N_("Activate Crash Handler."); o->type = CompOptionTypeBool; o->value.b = CRASHHANDLER_DISPLAY_OPTION_ENABLED_DEFAULT; o = &cd->opt[CRASHHANDLER_DISPLAY_OPTION_START_WM]; o->advanced = False; o->name = "start_window_manager"; o->group = N_("Misc. settings"); o->subGroup = N_(""); o->displayHints = ""; o->shortDesc = N_("Start Other Window Manager"); o->longDesc = N_("Start other window manager on Crash."); o->type = CompOptionTypeBool; o->value.b = CRASHHANDLER_DISPLAY_OPTION_START_WM_DEFAULT; o = &cd->opt[CRASHHANDLER_DISPLAY_OPTION_WM]; o->advanced = False; o->name = "window_manager_command_line"; o->group = N_("Misc. settings"); o->subGroup = N_(""); o->displayHints = "command;"; o->shortDesc = N_("Window Manager Command Line"); o->longDesc = N_("Window manager command line. DO NOT ENTER BERYL HERE!!!"); o->type = CompOptionTypeString; o->value.s = strdup(CRASHHANDLER_DISPLAY_OPTION_WM_DEFAULT); o->rest.s.string = 0; o->rest.s.nString = 0; } static CompOption *crashhandlerGetDisplayOptions(CompDisplay * display, int *count) { if (display) { CRASHHANDLER_DISPLAY(display); *count = NUM_OPTIONS(cd); return cd->opt; } else { CrashhandlerDisplay *cd = malloc(sizeof(CrashhandlerDisplay)); crashhandlerDisplayInitOptions(cd); *count = NUM_OPTIONS(cd); return cd->opt; } } static Bool crashhandlerInitDisplay(CompPlugin * p, CompDisplay * d) { //Generate a bench display CrashhandlerDisplay *cd = (CrashhandlerDisplay *) malloc(sizeof(CrashhandlerDisplay)); //Allocate a private index cd->screenPrivateIndex = allocateScreenPrivateIndex(d); //Check if its valid if (cd->screenPrivateIndex < 0) { //Its invalid so free memory and return free(cd); return FALSE; } crashhandlerDisplayInitOptions(cd); cDisplay = d; if (cd->opt[CRASHHANDLER_DISPLAY_OPTION_ENABLED].value.b) { // segmentation fault signal(SIGSEGV, crash_handler); // floating point exception signal(SIGFPE, crash_handler); // illegal instruction signal(SIGILL, crash_handler); // abort signal(SIGABRT, crash_handler); } //Record the display d->privates[displayPrivateIndex].ptr = cd; return TRUE; } static void crashhandlerFiniDisplay(CompPlugin * p, CompDisplay * d) { signal(SIGSEGV, SIG_DFL); CRASHHANDLER_DISPLAY(d); //Free the private index freeScreenPrivateIndex(d, cd->screenPrivateIndex); //Free the pointer free(cd); } static Bool crashhandlerInit(CompPlugin * p) { displayPrivateIndex = allocateDisplayPrivateIndex(); if (displayPrivateIndex < 0) return FALSE; return TRUE; } static void crashhandlerFini(CompPlugin * p) { if (displayPrivateIndex >= 0) freeDisplayPrivateIndex(displayPrivateIndex); } CompPluginVTable crashhandlerVTable = { "crashhandler", N_("Crash handler"), N_("Beryl crash handler plugin"), crashhandlerInit, crashhandlerFini, crashhandlerInitDisplay, crashhandlerFiniDisplay, 0, 0, 0, 0, crashhandlerGetDisplayOptions, crashhandlerSetDisplayOption, 0, 0, 0, 0, 0, 0, BERYL_ABI_INFO, "beryl-plugins", "devel", 0, 0, False, }; CompPluginVTable *getCompPluginInfo(void) { return &crashhandlerVTable; }