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 <string.h>
00029 #include <signal.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <unistd.h>
00033 #include "kcrash.h"
00034 
00035 #include <sys/types.h>
00036 #include <sys/time.h>
00037 #include <sys/resource.h>
00038 #include <sys/wait.h>
00039 
00040 #include <qwindowdefs.h> 
00041 #include <kglobal.h>
00042 #include <kinstance.h>
00043 #include <kaboutdata.h>
00044 #include <kdebug.h>
00045 #include <kapplication.h>
00046 #include <dcopclient.h>
00047 
00048 #ifdef Q_WS_X11
00049 #include <X11/Xlib.h>
00050 #endif
00051 
00052 KCrash::HandlerType KCrash::_emergencySaveFunction = 0;
00053 KCrash::HandlerType KCrash::_crashHandler = 0;
00054 const char *KCrash::appName = 0;
00055 const char *KCrash::appPath = 0;
00056 
00057 // This function sets the function which should be called when the 
00058 // application crashes and the
00059 // application is asked to try to save its data.
00060 void
00061 KCrash::setEmergencySaveFunction (HandlerType saveFunction)
00062 {
00063   _emergencySaveFunction = saveFunction;
00064   
00065   /* 
00066    * We need at least the default crash handler for 
00067    * emergencySaveFunction to be called
00068    */
00069   if (_emergencySaveFunction && !_crashHandler)
00070     _crashHandler = defaultCrashHandler;
00071 }
00072 
00073 
00074 // This function sets the function which should be responsible for 
00075 // the application crash handling.
00076 void
00077 KCrash::setCrashHandler (HandlerType handler)
00078 {
00079   if (!handler)
00080     handler = SIG_DFL;
00081 
00082   sigset_t mask;
00083   sigemptyset(&mask);
00084 
00085 #ifdef SIGSEGV
00086   signal (SIGSEGV, handler);
00087   sigaddset(&mask, SIGSEGV);
00088 #endif
00089 #ifdef SIGFPE
00090   signal (SIGFPE, handler);
00091   sigaddset(&mask, SIGFPE);
00092 #endif
00093 #ifdef SIGILL
00094   signal (SIGILL, handler);
00095   sigaddset(&mask, SIGILL);
00096 #endif
00097 #ifdef SIGABRT
00098   signal (SIGABRT, handler);
00099   sigaddset(&mask, SIGABRT);
00100 #endif
00101 
00102   sigprocmask(SIG_UNBLOCK, &mask, 0);
00103 
00104   _crashHandler = handler;
00105 }
00106 
00107 void
00108 KCrash::defaultCrashHandler (int sig)
00109 {
00110   // WABA: Do NOT use kdDebug() in this function because it is much too risky!
00111   // Handle possible recursions
00112   static int crashRecursionCounter = 0;
00113   crashRecursionCounter++; // Nothing before this, please !
00114 
00115   signal(SIGALRM, SIG_DFL);
00116   alarm(3); // Kill me... (in case we deadlock in malloc)
00117 
00118   if (crashRecursionCounter < 2) {
00119     if (_emergencySaveFunction) {
00120       _emergencySaveFunction (sig);
00121     }
00122     crashRecursionCounter++; // 
00123   }
00124   
00125         // Close dcop connections
00126   DCOPClient::emergencyClose();
00127   // Close all remaining file descriptors
00128   struct rlimit rlp;
00129   getrlimit(RLIMIT_NOFILE, &rlp);
00130   for (int i = 0; i < (int)rlp.rlim_cur; i++)
00131     close(i);
00132 
00133   if (crashRecursionCounter < 3)
00134   {
00135     if (appName) 
00136     {
00137 #ifndef NDEBUG
00138       fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter);
00139       fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid());
00140 #else
00141       fprintf(stderr, "KCrash: Application '%s' crashing...\n", appName ? appName : "<unknown>");
00142 #endif
00143 
00144       pid_t pid = fork();
00145 
00146       if (pid <= 0) {
00147         // this code is leaking, but this should not hurt cause we will do a
00148         // exec() afterwards. exec() is supposed to clean up.
00149         char * argv[18]; // don't forget to update this
00150         int i = 0;
00151 
00152         // argument 0 has to be drkonqi
00153         argv[i++] = qstrdup("drkonqi");
00154 
00155         // start up on the correct display
00156         argv[i++] = qstrdup("-display");
00157 #ifdef Q_WS_X11
00158         if ( qt_xdisplay() )
00159           argv[i++] = XDisplayString(qt_xdisplay());
00160         else
00161           argv[i++] = getenv("DISPLAY");
00162 #elif defined(Q_WS_QWS)
00163     argv[i++] = getenv("QWS_DISPLAY");
00164 #endif
00165 
00166         // we have already tested this
00167         argv[i++] = qstrdup("--appname");
00168         argv[i++] = qstrdup(appName);
00169         if (KApplication::loadedByKdeinit)
00170           argv[i++] = qstrdup("--kdeinit");
00171 
00172         // only add apppath if it's not NULL
00173         if (appPath) {
00174           argv[i++] = qstrdup("--apppath");
00175           argv[i++] = qstrdup(appPath);
00176         }
00177 
00178         // signal number -- will never be NULL
00179         QCString tmp;
00180         tmp.setNum(sig);
00181         argv[i++] = qstrdup("--signal");
00182         argv[i++] = qstrdup(tmp.data());
00183 
00184         // pid number -- only include if this is the child
00185         // the debug stuff will be disabled if we was not able to fork
00186         if (pid == 0) {
00187       tmp.setNum(getppid());
00188           argv[i++] = qstrdup("--pid");
00189       argv[i++] = qstrdup(tmp.data());
00190         }
00191 
00192         const KInstance *instance = KGlobal::_instance;
00193         const KAboutData *about = instance ? instance->aboutData() : 0;
00194         if (about) {
00195       if (!about->version().isNull()) {
00196         argv[i++] = qstrdup("--appversion");
00197         argv[i++] = qstrdup(about->version().utf8());
00198       }
00199 
00200       if (!about->programName().isNull()) {
00201         argv[i++] = qstrdup("--programname");
00202         argv[i++] = qstrdup(about->programName().utf8());
00203       }
00204 
00205       if (!about->bugAddress().isNull()) {
00206         argv[i++] = qstrdup("--bugaddress");
00207         argv[i++] = qstrdup(about->bugAddress().utf8());
00208       }
00209         }
00210 
00211     if ( kapp && !kapp->startupId().isNull()) {
00212         argv[i++] = qstrdup("--startupid");
00213         argv[i++] = qstrdup(kapp->startupId());
00214     }
00215 
00216         // NULL terminated list
00217         argv[i++] = NULL;
00218 
00219         setgid(getgid());
00220         setuid(getuid());
00221 
00222         execvp("drkonqi", argv);
00223 
00224         // we could clean up here
00225         // i = 0;
00226         // while (argv[i])
00227         //   free(argv[i++]);
00228       }
00229       else
00230       {
00231           
00232         alarm(0); // Seems we made it....
00233 
00234         // wait for child to exit
00235         waitpid(pid, NULL, 0);
00236         _exit(253);
00237       }
00238     }
00239     else {
00240       fprintf(stderr, "Unknown appname\n");
00241     }
00242   }
00243    
00244   if (crashRecursionCounter < 4)
00245   {
00246      fprintf(stderr, "Unable to start Dr. Konqi\n");
00247   }
00248   _exit(255);
00249 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:46 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001