diff options
Diffstat (limited to 'soundserver/crashhandler.cpp')
-rw-r--r-- | soundserver/crashhandler.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/soundserver/crashhandler.cpp b/soundserver/crashhandler.cpp new file mode 100644 index 0000000..5864d89 --- /dev/null +++ b/soundserver/crashhandler.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2003 Stefan Westerfeld + * + * This code is based on code from the KDE Libraries + * Copyright (C) 2000 Timo Hummel <[email protected]> + * Tom Braun <[email protected]> + * + * 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 <string.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include "crashhandler.h" +#include "audiosubsys.h" +#include "debug.h" +#include "config.h" + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> + +#ifdef HAVE_REALTIME_SCHED +#include <sched.h> +#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 : "<unknown>" , appPath ? appPath : "<unknown>", getpid()); +#else + fprintf(stderr, "CrashHandler: Application '%s' crashing...\n", appName ? appName : "<unknown>"); +#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); +} |