diff options
Diffstat (limited to 'kdecore/kcrash.cpp')
-rw-r--r-- | kdecore/kcrash.cpp | 524 |
1 files changed, 0 insertions, 524 deletions
diff --git a/kdecore/kcrash.cpp b/kdecore/kcrash.cpp deleted file mode 100644 index dbbd41338..000000000 --- a/kdecore/kcrash.cpp +++ /dev/null @@ -1,524 +0,0 @@ -/* - * This file is part of 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 "config.h" - -#include <string.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> -#include "kcrash.h" - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/wait.h> -#include <sys/un.h> -#include <sys/socket.h> -#include <errno.h> - -#include <tqwindowdefs.h> -#include <kglobal.h> -#include <kinstance.h> -#include <kaboutdata.h> -#include <kdebug.h> -#include <kapplication.h> -#include <dcopclient.h> - -#include <../kinit/klauncher_cmds.h> - -#if defined Q_WS_X11 -#include <X11/Xlib.h> -#endif - -KCrash::HandlerType KCrash::_emergencySaveFunction = 0; -KCrash::HandlerType KCrash::_crashHandler = 0; -const char *KCrash::appName = 0; -const char *KCrash::appPath = 0; -bool KCrash::safer = false; - -// This function sets the function which should be called when the -// application crashes and the -// application is asked to try to save its data. -void -KCrash::setEmergencySaveFunction (HandlerType saveFunction) -{ - _emergencySaveFunction = saveFunction; - - /* - * We need at least the default crash handler for - * emergencySaveFunction to be called - */ - if (_emergencySaveFunction && !_crashHandler) - _crashHandler = defaultCrashHandler; -} - - -// This function sets the function which should be responsible for -// the application crash handling. -void -KCrash::setCrashHandler (HandlerType handler) -{ -#ifdef Q_OS_UNIX - 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); -#endif //Q_OS_UNIX - - _crashHandler = handler; -} - -void -KCrash::defaultCrashHandler (int sig) -{ -#ifdef Q_OS_UNIX - // 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) { - if (_emergencySaveFunction) { - _emergencySaveFunction (sig); - } - crashRecursionCounter++; // - } - - // Close all remaining file descriptors except for stdin/stdout/stderr - struct rlimit rlp; - getrlimit(RLIMIT_NOFILE, &rlp); - for (int i = 3; i < (int)rlp.rlim_cur; i++) - close(i); - - - // this code is leaking, but this should not hurt cause we will do a - // exec() afterwards. exec() is supposed to clean up. - if (crashRecursionCounter < 3) - { - if (appName) - { -#ifndef NDEBUG - fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter); - fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid()); -#else - fprintf(stderr, "KCrash: Application '%s' crashing...\n", appName ? appName : "<unknown>"); -#endif - - const char * argv[24]; // don't forget to update this - int i = 0; - - // argument 0 has to be drkonqi - argv[i++] = "drkonqi"; - -#if defined Q_WS_X11 - // start up on the correct display - argv[i++] = "-display"; - if ( qt_xdisplay() ) - argv[i++] = XDisplayString(qt_xdisplay()); - else - argv[i++] = getenv("DISPLAY"); -#elif defined(Q_WS_QWS) - // start up on the correct display - argv[i++] = "-display"; - argv[i++] = getenv("QWS_DISPLAY"); -#endif - - // we have already tested this - argv[i++] = "--appname"; - argv[i++] = appName; - if (KApplication::loadedByKdeinit) - argv[i++] = "--tdeinit"; - - // only add apppath if it's not NULL - if (appPath) { - argv[i++] = "--apppath"; - argv[i++] = appPath; - } - - // signal number -- will never be NULL - char sigtxt[ 10 ]; - sprintf( sigtxt, "%d", sig ); - argv[i++] = "--signal"; - argv[i++] = sigtxt; - - char pidtxt[ 10 ]; - sprintf( pidtxt, "%d", getpid()); - argv[i++] = "--pid"; - argv[i++] = pidtxt; - - const KInstance *instance = KGlobal::_instance; - const KAboutData *about = instance ? instance->aboutData() : 0; - if (about) { - if (about->internalVersion()) { - argv[i++] = "--appversion"; - argv[i++] = about->internalVersion(); - } - - if (about->internalProgramName()) { - argv[i++] = "--programname"; - argv[i++] = about->internalProgramName(); - } - - if (about->internalBugAddress()) { - argv[i++] = "--bugaddress"; - argv[i++] = about->internalBugAddress(); - } - } - - if ( kapp && !kapp->startupId().isNull()) { - argv[i++] = "--startupid"; - argv[i++] = kapp->startupId().data(); - } - - if ( safer ) - argv[i++] = "--safer"; - - // NULL terminated list - argv[i] = NULL; - - startDrKonqi( argv, i ); - _exit(253); - - } - else { - fprintf(stderr, "Unknown appname\n"); - } - } - - if (crashRecursionCounter < 4) - { - fprintf(stderr, "Unable to start Dr. Konqi\n"); - } -#endif //Q_OS_UNIX - - _exit(255); -} - -#ifdef Q_OS_UNIX - -// Since we can't fork() in the crashhandler, we cannot execute any external code -// (there can be functions registered to be performed before fork(), for example -// handling of malloc locking, which doesn't work when malloc crashes because of heap corruption). - -static int write_socket(int sock, char *buffer, int len); -static int read_socket(int sock, char *buffer, int len); -static int openSocket(); - -void KCrash::startDrKonqi( const char* argv[], int argc ) -{ - int socket = openSocket(); - if( socket < -1 ) - { - startDirectly( argv, argc ); - return; - } - klauncher_header header; - header.cmd = LAUNCHER_EXEC_NEW; - const int BUFSIZE = 8192; // make sure this is big enough - char buffer[ BUFSIZE + 10 ]; - int pos = 0; - long argcl = argc; - memcpy( buffer + pos, &argcl, sizeof( argcl )); - pos += sizeof( argcl ); - for( int i = 0; - i < argc; - ++i ) - { - int len = strlen( argv[ i ] ) + 1; // include terminating \0 - if( pos + len > BUFSIZE ) - { - fprintf( stderr, "BUFSIZE in KCrash not big enough!\n" ); - startDirectly( argv, argc ); - return; - } - memcpy( buffer + pos, argv[ i ], len ); - pos += len; - } - long env = 0; - memcpy( buffer + pos, &env, sizeof( env )); - pos += sizeof( env ); - long avoid_loops = 0; - memcpy( buffer + pos, &avoid_loops, sizeof( avoid_loops )); - pos += sizeof( avoid_loops ); - header.arg_length = pos; - write_socket(socket, (char *) &header, sizeof(header)); - write_socket(socket, buffer, pos); - if( read_socket( socket, (char *) &header, sizeof(header)) < 0 - || header.cmd != LAUNCHER_OK ) - { - startDirectly( argv, argc ); - return; - } - long pid; - read_socket(socket, buffer, header.arg_length); - pid = *((long *) buffer); - - alarm(0); // Seems we made it.... - - for(;;) - { - if( kill( pid, 0 ) < 0 ) - _exit(253); - sleep(1); - // the debugger should stop this process anyway - } -} - -// If we can't reach tdeinit we can still at least try to fork() -void KCrash::startDirectly( const char* argv[], int ) -{ - fprintf( stderr, "KCrash cannot reach tdeinit, launching directly.\n" ); - pid_t pid = fork(); - if (pid <= 0) - { - if(!geteuid() && setgid(getgid()) < 0) - _exit(253); - if(!geteuid() && setuid(getuid()) < 0) - _exit(253); - execvp("drkonqi", const_cast< char** >( argv )); - _exit(errno); - } - else - { - alarm(0); // Seems we made it.... - // wait for child to exit - waitpid(pid, NULL, 0); - _exit(253); - } -} - -// From now on this code is copy&pasted from kinit/wrapper.c : - -extern char **environ; - -static char *getDisplay() -{ - const char *display; - char *result; - char *screen; - char *colon; - char *i; -/* - don't test for a value from tqglobal.h but instead distinguish - Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS - on the commandline (which in tqglobal.h however triggers Q_WS_QWS, - but we don't want to include that here) (Simon) -#ifdef Q_WS_X11 - */ -#if !defined(QWS) - display = getenv("DISPLAY"); -#else - display = getenv("QWS_DISPLAY"); -#endif - if (!display || !*display) - { - display = ":0"; - } - result = (char*)malloc(strlen(display)+1); - if (result == NULL) - return NULL; - - strcpy(result, display); - screen = strrchr(result, '.'); - colon = strrchr(result, ':'); - if (screen && (screen > colon)) - *screen = '\0'; - while((i = strchr(result, ':'))) - *i = '_'; - return result; -} - -/* - * Write 'len' bytes from 'buffer' into 'sock'. - * returns 0 on success, -1 on failure. - */ -static int write_socket(int sock, char *buffer, int len) -{ - ssize_t result; - int bytes_left = len; - while ( bytes_left > 0) - { - result = write(sock, buffer, bytes_left); - if (result > 0) - { - buffer += result; - bytes_left -= result; - } - else if (result == 0) - return -1; - else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN)) - return -1; - } - return 0; -} - -/* - * Read 'len' bytes from 'sock' into 'buffer'. - * returns 0 on success, -1 on failure. - */ -static int read_socket(int sock, char *buffer, int len) -{ - ssize_t result; - int bytes_left = len; - while ( bytes_left > 0) - { - result = read(sock, buffer, bytes_left); - if (result > 0) - { - buffer += result; - bytes_left -= result; - } - else if (result == 0) - return -1; - else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN)) - return -1; - } - return 0; -} - -static int openSocket() -{ - kde_socklen_t socklen; - int s; - struct sockaddr_un server; -#define MAX_SOCK_FILE 255 - char sock_file[MAX_SOCK_FILE + 1]; - const char *home_dir = getenv("HOME"); - const char *kde_home = getenv("KDEHOME"); - char *display; - - sock_file[0] = sock_file[MAX_SOCK_FILE] = 0; - - if (!kde_home || !kde_home[0]) - { - kde_home = "~/.trinity/"; - } - - if (kde_home[0] == '~') - { - if (!home_dir || !home_dir[0]) - { - fprintf(stderr, "Warning: $HOME not set!\n"); - return -1; - } - if (strlen(home_dir) > (MAX_SOCK_FILE-100)) - { - fprintf(stderr, "Warning: Home directory path too long!\n"); - return -1; - } - kde_home++; - strncpy(sock_file, home_dir, MAX_SOCK_FILE); - } - strncat(sock_file, kde_home, MAX_SOCK_FILE - strlen(sock_file)); - - /** Strip trailing '/' **/ - if ( sock_file[strlen(sock_file)-1] == '/') - sock_file[strlen(sock_file)-1] = 0; - - strncat(sock_file, "/socket-", MAX_SOCK_FILE - strlen(sock_file)); - if( getenv("XAUTHLOCALHOSTNAME")) - strncat(sock_file, getenv("XAUTHLOCALHOSTNAME"), MAX_SOCK_FILE - strlen(sock_file) - 1); - else if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0) - { - perror("Warning: Could not determine hostname: "); - return -1; - } - sock_file[sizeof(sock_file)-1] = '\0'; - - /* append $DISPLAY */ - display = getDisplay(); - if (display == NULL) - { - fprintf(stderr, "Error: Could not determine display.\n"); - return -1; - } - - if (strlen(sock_file)+strlen(display)+strlen("/tdeinit_")+2 > MAX_SOCK_FILE) - { - fprintf(stderr, "Warning: Socket name will be too long.\n"); - free(display); - return -1; - } - strcat(sock_file, "/tdeinit_"); - strcat(sock_file, display); - free(display); - - if (strlen(sock_file) >= sizeof(server.sun_path)) - { - fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n"); - return -1; - } - - /* - * create the socket stream - */ - s = socket(PF_UNIX, SOCK_STREAM, 0); - if (s < 0) - { - perror("Warning: socket() failed: "); - return -1; - } - - server.sun_family = AF_UNIX; - strcpy(server.sun_path, sock_file); - socklen = sizeof(server); - if(connect(s, (struct sockaddr *)&server, socklen) == -1) - { - perror("Warning: connect() failed: "); - close(s); - return -1; - } - return s; -} - -#endif // Q_OS_UNIX |