kdecore Library API Documentation

kcrash.cpp

00001 /*
00002  * This file is part of the KDE Libraries
00003  * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com>
00004  *                    Tom Braun <braunt@fh-konstanz.de>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public License
00017  * along with this library; see the file COPYING.LIB.  If not, write to
00018  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019  * Boston, MA 02111-1307, USA.
00020  */
00021 
00022 /*
00023  * This file is used to catch signals which would normally
00024  * crash the application (like segmentation fault, floating
00025  * point exception and such).
00026  */
00027 
00028 #include "config.h"
00029 
00030 #include <string.h>
00031 #include <signal.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include "kcrash.h"
00036 
00037 #include <sys/types.h>
00038 #include <sys/time.h>
00039 #include <sys/resource.h>
00040 #include <sys/wait.h>
00041 
00042 #include <qwindowdefs.h>
00043 #include <kglobal.h>
00044 #include <kinstance.h>
00045 #include <kaboutdata.h>
00046 #include <kdebug.h>
00047 #include <kapplication.h>
00048 #include <dcopclient.h>
00049 
00050 #if defined Q_WS_X11
00051 #include <X11/Xlib.h>
00052 #endif
00053 
00054 KCrash::HandlerType KCrash::_emergencySaveFunction = 0;
00055 KCrash::HandlerType KCrash::_crashHandler = 0;
00056 const char *KCrash::appName = 0;
00057 const char *KCrash::appPath = 0;
00058 bool KCrash::safer = false;
00059 
00060 // This function sets the function which should be called when the
00061 // application crashes and the
00062 // application is asked to try to save its data.
00063 void
00064 KCrash::setEmergencySaveFunction (HandlerType saveFunction)
00065 {
00066   _emergencySaveFunction = saveFunction;
00067 
00068   /*
00069    * We need at least the default crash handler for
00070    * emergencySaveFunction to be called
00071    */
00072   if (_emergencySaveFunction && !_crashHandler)
00073     _crashHandler = defaultCrashHandler;
00074 }
00075 
00076 
00077 // This function sets the function which should be responsible for
00078 // the application crash handling.
00079 void
00080 KCrash::setCrashHandler (HandlerType handler)
00081 {
00082 #ifdef Q_OS_UNIX
00083   if (!handler)
00084     handler = SIG_DFL;
00085 
00086   sigset_t mask;
00087   sigemptyset(&mask);
00088 
00089 #ifdef SIGSEGV
00090   signal (SIGSEGV, handler);
00091   sigaddset(&mask, SIGSEGV);
00092 #endif
00093 #ifdef SIGFPE
00094   signal (SIGFPE, handler);
00095   sigaddset(&mask, SIGFPE);
00096 #endif
00097 #ifdef SIGILL
00098   signal (SIGILL, handler);
00099   sigaddset(&mask, SIGILL);
00100 #endif
00101 #ifdef SIGABRT
00102   signal (SIGABRT, handler);
00103   sigaddset(&mask, SIGABRT);
00104 #endif
00105 
00106   sigprocmask(SIG_UNBLOCK, &mask, 0);
00107 #endif //Q_OS_UNIX
00108 
00109   _crashHandler = handler;
00110 }
00111 
00112 void
00113 KCrash::defaultCrashHandler (int sig)
00114 {
00115 #ifdef Q_OS_UNIX
00116   // WABA: Do NOT use kdDebug() in this function because it is much too risky!
00117   // Handle possible recursions
00118   static int crashRecursionCounter = 0;
00119   crashRecursionCounter++; // Nothing before this, please !
00120 
00121   signal(SIGALRM, SIG_DFL);
00122   alarm(3); // Kill me... (in case we deadlock in malloc)
00123 
00124   if (crashRecursionCounter < 2) {
00125     if (_emergencySaveFunction) {
00126       _emergencySaveFunction (sig);
00127     }
00128     crashRecursionCounter++; //
00129   }
00130 
00131         // Close dcop connections
00132   DCOPClient::emergencyClose();
00133   // Close all remaining file descriptors except for stdin/stdout/stderr
00134   struct rlimit rlp;
00135   getrlimit(RLIMIT_NOFILE, &rlp);
00136   for (int i = 3; i < (int)rlp.rlim_cur; i++)
00137     close(i);
00138 
00139   bool shuttingDown = false;
00140 
00141   // don't load drkonqi during shutdown
00142   if ( !shuttingDown )
00143   {
00144     if (crashRecursionCounter < 3)
00145     {
00146       if (appName)
00147       {
00148 #ifndef NDEBUG
00149         fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter);
00150         fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid());
00151 #else
00152         fprintf(stderr, "KCrash: Application '%s' crashing...\n", appName ? appName : "<unknown>");
00153 #endif
00154 
00155         pid_t pid = fork();
00156 
00157         if (pid <= 0) {
00158           // this code is leaking, but this should not hurt cause we will do a
00159           // exec() afterwards. exec() is supposed to clean up.
00160           char * argv[24]; // don't forget to update this
00161           int i = 0;
00162 
00163           // argument 0 has to be drkonqi
00164           argv[i++] = qstrdup("drkonqi");
00165 
00166 #if defined Q_WS_X11
00167           // start up on the correct display
00168           argv[i++] = qstrdup("-display");
00169           if ( qt_xdisplay() )
00170             argv[i++] = XDisplayString(qt_xdisplay());
00171           else
00172             argv[i++] = getenv("DISPLAY");
00173 #elif defined(Q_WS_QWS)
00174           // start up on the correct display
00175           argv[i++] = qstrdup("-display");
00176           argv[i++] = getenv("QWS_DISPLAY");
00177 #endif
00178 
00179           // we have already tested this
00180           argv[i++] = qstrdup("--appname");
00181           argv[i++] = qstrdup(appName);
00182           if (KApplication::loadedByKdeinit)
00183             argv[i++] = qstrdup("--kdeinit");
00184 
00185           // only add apppath if it's not NULL
00186           if (appPath) {
00187             argv[i++] = qstrdup("--apppath");
00188             argv[i++] = qstrdup(appPath);
00189           }
00190 
00191           // signal number -- will never be NULL
00192           QCString tmp;
00193           tmp.setNum(sig);
00194           argv[i++] = qstrdup("--signal");
00195           argv[i++] = qstrdup(tmp.data());
00196 
00197           // pid number -- only include if this is the child
00198           // the debug stuff will be disabled if we was not able to fork
00199           if (pid == 0) {
00200             tmp.setNum(getppid());
00201             argv[i++] = qstrdup("--pid");
00202             argv[i++] = qstrdup(tmp.data());
00203           }
00204 
00205           const KInstance *instance = KGlobal::_instance;
00206           const KAboutData *about = instance ? instance->aboutData() : 0;
00207           if (about) {
00208             if (!about->version().isNull()) {
00209               argv[i++] = qstrdup("--appversion");
00210               argv[i++] = qstrdup(about->version().utf8());
00211             }
00212 
00213             if (!about->programName().isNull()) {
00214               argv[i++] = qstrdup("--programname");
00215               argv[i++] = qstrdup(about->programName().utf8());
00216             }
00217 
00218             if (!about->bugAddress().isNull()) {
00219               argv[i++] = qstrdup("--bugaddress");
00220               argv[i++] = qstrdup(about->bugAddress().utf8());
00221             }
00222           }
00223 
00224           if ( kapp && !kapp->startupId().isNull()) {
00225             argv[i++] = qstrdup("--startupid");
00226             argv[i++] = qstrdup(kapp->startupId());
00227           }
00228 
00229           if ( safer )
00230             argv[i++] = qstrdup("--safer");
00231 
00232           // NULL terminated list
00233           argv[i++] = NULL;
00234 
00235           setgid(getgid());
00236           setuid(getuid());
00237 
00238           execvp("drkonqi", argv);
00239 
00240           // we could clean up here
00241           // i = 0;
00242           // while (argv[i])
00243           //   free(argv[i++]);
00244         }
00245         else
00246         {
00247 
00248           alarm(0); // Seems we made it....
00249 
00250           // wait for child to exit
00251           waitpid(pid, NULL, 0);
00252           _exit(253);
00253         }
00254       }
00255       else {
00256         fprintf(stderr, "Unknown appname\n");
00257       }
00258     }
00259 
00260     if (crashRecursionCounter < 4)
00261     {
00262       fprintf(stderr, "Unable to start Dr. Konqi\n");
00263     }
00264   }
00265 #endif //Q_OS_UNIX
00266 
00267   _exit(255);
00268 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 9 07:54:00 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003