/**
*
* 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <beryl.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1