You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
arts/soundserver/crashhandler.cc

237 lines
6.3 KiB

/*
* Copyright (C) 2003 Stefan Westerfeld
*
* This code is based on code from the KDE Libraries
* Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
* Tom Braun <braunt@fh-konstanz.de>
*
* 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 tqmask;
sigemptyset(&tqmask);
#ifdef SIGSEGV
signal (SIGSEGV, handler);
sigaddset(&tqmask, SIGSEGV);
#endif
#ifdef SIGFPE
signal (SIGFPE, handler);
sigaddset(&tqmask, SIGFPE);
#endif
#ifdef SIGILL
signal (SIGILL, handler);
sigaddset(&tqmask, SIGILL);
#endif
#ifdef SIGABRT
signal (SIGABRT, handler);
sigaddset(&tqmask, SIGABRT);
#endif
sigprocmask(SIG_UNBLOCK, &tqmask, 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);
}