/* * Copyright (C) 2003 Stefan Westerfeld * * This code is based on code from the KDE Libraries * Copyright (C) 2000 Timo Hummel * Tom Braun * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * This file is used to catch signals which would normally * crash the application (like segmentation fault, floating * point exception and such). */ #include #include #include #include #include #include #include "crashhandler.h" #include "audiosubsys.h" #include "debug.h" #include "config.h" #include #include #include #include #ifdef HAVE_REALTIME_SCHED #include #endif using namespace Arts; CrashHandler::HandlerType CrashHandler::_crashHandler = 0; const char *CrashHandler::appName = 0; const char *CrashHandler::appPath = 0; const char *CrashHandler::appVersion = 0; const char *CrashHandler::programName = 0; const char *CrashHandler::bugAddress = 0; const char *CrashHandler::crashApp = 0; // This function sets the function which should be responsible for // the application crash handling. void CrashHandler::setCrashHandler (HandlerType handler) { if (!handler) handler = SIG_DFL; sigset_t mask; sigemptyset(&mask); #ifdef SIGSEGV signal (SIGSEGV, handler); sigaddset(&mask, SIGSEGV); #endif #ifdef SIGFPE signal (SIGFPE, handler); sigaddset(&mask, SIGFPE); #endif #ifdef SIGILL signal (SIGILL, handler); sigaddset(&mask, SIGILL); #endif #ifdef SIGABRT signal (SIGABRT, handler); sigaddset(&mask, SIGABRT); #endif sigprocmask(SIG_UNBLOCK, &mask, 0); _crashHandler = handler; } void CrashHandler::defaultCrashHandler (int sig) { // WABA: Do NOT use kdDebug() in this function because it is much too risky! // Handle possible recursions static int crashRecursionCounter = 0; crashRecursionCounter++; // Nothing before this, please ! signal(SIGALRM, SIG_DFL); alarm(3); // Kill me... (in case we deadlock in malloc) if (crashRecursionCounter < 2) { Arts::AudioSubSystem *a = Arts::AudioSubSystem::the(); if(a) a->emergencyCleanup(); #ifdef HAVE_REALTIME_SCHED struct sched_param sp; sp.sched_priority = 0; if (sched_setscheduler(0, SCHED_OTHER, &sp) != 0) fprintf(stderr, "CrashHandler: can't stop running as realtime process (%s)\n", strerror(errno)); #endif crashRecursionCounter++; // } // Close all remaining file descriptors struct rlimit rlp; getrlimit(RLIMIT_NOFILE, &rlp); for (int i = 0; i < (int)rlp.rlim_cur; i++) close(i); bool shuttingDown = false; // don't load drkonqi during shutdown if ( !shuttingDown ) { if (crashRecursionCounter < 3) { if (appName) { #ifndef NDEBUG fprintf(stderr, "CrashHandler: crashing... crashRecursionCounter = %d\n", crashRecursionCounter); fprintf(stderr, "CrashHandler: Application Name = %s path = %s pid = %d\n", appName ? appName : "" , appPath ? appPath : "", getpid()); #else fprintf(stderr, "CrashHandler: Application '%s' crashing...\n", appName ? appName : ""); #endif pid_t pid = fork(); if (pid <= 0) { // this code is leaking, but this should not hurt cause we will do a // exec() afterwards. exec() is supposed to clean up. char * argv[18]; // don't forget to update this int i = 0; // argument 0 has to be drkonqi argv[i++] = strdup(crashApp); char *display = getenv("DISPLAY"); if (display) { // start up on the correct display argv[i++] = strdup("-display"); argv[i++] = display; } // we have already tested this argv[i++] = strdup("--appname"); argv[i++] = strdup(appName); // only add apppath if it's not NULL if (appPath) { argv[i++] = strdup("--apppath"); argv[i++] = strdup(appPath); } // signal number -- will never be NULL argv[i++] = strdup("--signal"); argv[i++] = arts_strdup_printf("%d", sig); // pid number -- only include if this is the child // the debug stuff will be disabled if we was not able to fork if (pid == 0) { argv[i++] = strdup("--pid"); argv[i++] = arts_strdup_printf("%d", getppid()); } if (appVersion) { argv[i++] = strdup("--appversion"); argv[i++] = strdup(appVersion); } if (programName) { argv[i++] = strdup("--programname"); argv[i++] = strdup(programName); } if (bugAddress) { argv[i++] = strdup("--bugaddress"); argv[i++] = strdup(bugAddress); } // NULL terminated list argv[i++] = NULL; setgid(getgid()); if (getuid() != geteuid()) setuid(getuid()); if (getuid() != geteuid()) { perror("setuid()"); exit(255); } execvp(crashApp, argv); // we could clean up here // i = 0; // while (argv[i]) // free(argv[i++]); } else { alarm(0); // Seems we made it.... fprintf(stderr, "ArtsCrash: ... waiting for child to exit\n"); // wait for child to exit waitpid(pid, NULL, 0); _exit(253); } } else { fprintf(stderr, "Unknown appname\n"); } } if (crashRecursionCounter < 4) { fprintf(stderr, "Unable to start %s\n", crashApp); } } _exit(255); }