Logo Search packages:      
Sourcecode: beryl-plugins version File versions

crashhandler.c

/**
 *
 * 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;
}

Generated by  Doxygen 1.6.0   Back to index