• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kcrash.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, 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 <time.h>
00036 #include "kcrash.h"
00037 
00038 #include <sys/types.h>
00039 #include <sys/time.h>
00040 #include <sys/resource.h>
00041 #include <sys/wait.h>
00042 #include <sys/un.h>
00043 #include <sys/socket.h>
00044 #include <errno.h>
00045 
00046 #include <qwindowdefs.h>
00047 #include <kglobal.h>
00048 #include <kinstance.h>
00049 #include <kaboutdata.h>
00050 #include <kdebug.h>
00051 #include <kapplication.h>
00052 #include <dcopclient.h>
00053 
00054 #include <../kinit/klauncher_cmds.h>
00055 
00056 #if defined Q_WS_X11
00057 #include <X11/Xlib.h>
00058 #endif
00059 
00060 KCrash::HandlerType KCrash::_emergencySaveFunction = 0;
00061 KCrash::HandlerType KCrash::_crashHandler = 0;
00062 const char *KCrash::appName = 0;
00063 const char *KCrash::appPath = 0;
00064 bool KCrash::safer = false;
00065 
00066 // This function sets the function which should be called when the
00067 // application crashes and the
00068 // application is asked to try to save its data.
00069 void
00070 KCrash::setEmergencySaveFunction (HandlerType saveFunction)
00071 {
00072   _emergencySaveFunction = saveFunction;
00073 
00074   /*
00075    * We need at least the default crash handler for
00076    * emergencySaveFunction to be called
00077    */
00078   if (_emergencySaveFunction && !_crashHandler)
00079     _crashHandler = defaultCrashHandler;
00080 }
00081 
00082 
00083 // This function sets the function which should be responsible for
00084 // the application crash handling.
00085 void
00086 KCrash::setCrashHandler (HandlerType handler)
00087 {
00088 #ifdef Q_OS_UNIX
00089   if (!handler)
00090     handler = SIG_DFL;
00091 
00092   sigset_t mask;
00093   sigemptyset(&mask);
00094 
00095 #ifdef SIGSEGV
00096   signal (SIGSEGV, handler);
00097   sigaddset(&mask, SIGSEGV);
00098 #endif
00099 #ifdef SIGFPE
00100   signal (SIGFPE, handler);
00101   sigaddset(&mask, SIGFPE);
00102 #endif
00103 #ifdef SIGILL
00104   signal (SIGILL, handler);
00105   sigaddset(&mask, SIGILL);
00106 #endif
00107 #ifdef SIGABRT
00108   signal (SIGABRT, handler);
00109   sigaddset(&mask, SIGABRT);
00110 #endif
00111 
00112   sigprocmask(SIG_UNBLOCK, &mask, 0);
00113 #endif //Q_OS_UNIX
00114 
00115   _crashHandler = handler;
00116 }
00117 
00118 void
00119 KCrash::defaultCrashHandler (int sig)
00120 {
00121 #ifdef Q_OS_UNIX
00122   // WABA: Do NOT use kdDebug() in this function because it is much too risky!
00123   // Handle possible recursions
00124   static int crashRecursionCounter = 0;
00125   crashRecursionCounter++; // Nothing before this, please !
00126 
00127   signal(SIGALRM, SIG_DFL);
00128   alarm(3); // Kill me... (in case we deadlock in malloc)
00129 
00130   if (crashRecursionCounter < 2) {
00131     if (_emergencySaveFunction) {
00132       _emergencySaveFunction (sig);
00133     }
00134     crashRecursionCounter++; //
00135   }
00136 
00137   // Close all remaining file descriptors except for stdin/stdout/stderr
00138   struct rlimit rlp;
00139   getrlimit(RLIMIT_NOFILE, &rlp);
00140   for (int i = 3; i < (int)rlp.rlim_cur; i++)
00141     close(i);
00142 
00143 
00144   // this code is leaking, but this should not hurt cause we will do a
00145   // exec() afterwards. exec() is supposed to clean up.
00146     if (crashRecursionCounter < 3)
00147     {
00148       if (appName)
00149       {
00150 #ifndef NDEBUG
00151         fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n", crashRecursionCounter);
00152         fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %d\n", appName ? appName : "<unknown>" , appPath ? appPath : "<unknown>", getpid());
00153 #else
00154         fprintf(stderr, "KCrash: Application '%s' crashing...\n", appName ? appName : "<unknown>");
00155 #endif
00156 
00157           const char * argv[24]; // don't forget to update this
00158           int i = 0;
00159 
00160           // argument 0 has to be drkonqi
00161           argv[i++] = "drkonqi";
00162 
00163 #if defined Q_WS_X11
00164           // start up on the correct display
00165           argv[i++] = "-display";
00166           if ( qt_xdisplay() )
00167             argv[i++] = XDisplayString(qt_xdisplay());
00168           else
00169             argv[i++] = getenv("DISPLAY");
00170 #elif defined(Q_WS_QWS)
00171           // start up on the correct display
00172           argv[i++] = "-display";
00173           argv[i++] = getenv("QWS_DISPLAY");
00174 #endif
00175 
00176           // we have already tested this
00177           argv[i++] = "--appname";
00178           argv[i++] = appName;
00179           if (KApplication::loadedByKdeinit)
00180             argv[i++] = "--kdeinit";
00181 
00182           // only add apppath if it's not NULL
00183           if (appPath) {
00184             argv[i++] = "--apppath";
00185             argv[i++] = appPath;
00186           }
00187 
00188           // signal number -- will never be NULL
00189           char sigtxt[ 10 ];
00190           sprintf( sigtxt, "%d", sig );
00191           argv[i++] = "--signal";
00192           argv[i++] = sigtxt;
00193 
00194           char pidtxt[ 10 ];
00195           sprintf( pidtxt, "%d", getpid());
00196           argv[i++] = "--pid";
00197           argv[i++] = pidtxt;
00198 
00199           const KInstance *instance = KGlobal::_instance;
00200           const KAboutData *about = instance ? instance->aboutData() : 0;
00201           if (about) {
00202             if (about->internalVersion()) {
00203               argv[i++] = "--appversion";
00204               argv[i++] = about->internalVersion();
00205             }
00206 
00207             if (about->internalProgramName()) {
00208               argv[i++] = "--programname";
00209               argv[i++] = about->internalProgramName();
00210             }
00211 
00212             if (about->internalBugAddress()) {
00213               argv[i++] = "--bugaddress";
00214               argv[i++] = about->internalBugAddress();
00215             }
00216           }
00217 
00218           if ( kapp && !kapp->startupId().isNull()) {
00219             argv[i++] = "--startupid";
00220             argv[i++] = kapp->startupId().data();
00221           }
00222 
00223           if ( safer )
00224             argv[i++] = "--safer";
00225 
00226           // NULL terminated list
00227           argv[i] = NULL;
00228 
00229           startDrKonqi( argv, i );
00230           _exit(253);
00231 
00232       }
00233       else {
00234         fprintf(stderr, "Unknown appname\n");
00235       }
00236     }
00237 
00238     if (crashRecursionCounter < 4)
00239     {
00240       fprintf(stderr, "Unable to start Dr. Konqi\n");
00241     }
00242 #endif //Q_OS_UNIX
00243 
00244   _exit(255);
00245 }
00246 
00247 #ifdef Q_OS_UNIX
00248 
00249 // Since we can't fork() in the crashhandler, we cannot execute any external code
00250 // (there can be functions registered to be performed before fork(), for example
00251 // handling of malloc locking, which doesn't work when malloc crashes because of heap corruption).
00252 
00253 static int write_socket(int sock, char *buffer, int len);
00254 static int read_socket(int sock, char *buffer, int len);
00255 static int openSocket();
00256 
00257 void KCrash::startDrKonqi( const char* argv[], int argc )
00258 {
00259   int socket = openSocket();
00260   if( socket < -1 )
00261   {
00262     startDirectly( argv, argc );
00263     return;
00264   }
00265   klauncher_header header;
00266   header.cmd = LAUNCHER_EXEC_NEW;
00267   const int BUFSIZE = 8192; // make sure this is big enough
00268   char buffer[ BUFSIZE + 10 ];
00269   int pos = 0;
00270   long argcl = argc;
00271   memcpy( buffer + pos, &argcl, sizeof( argcl ));
00272   pos += sizeof( argcl );
00273   for( int i = 0;
00274        i < argc;
00275        ++i )
00276   {
00277     int len = strlen( argv[ i ] ) + 1; // include terminating \0
00278     if( pos + len > BUFSIZE )
00279     {
00280       fprintf( stderr, "BUFSIZE in KCrash not big enough!\n" );
00281       startDirectly( argv, argc );
00282       return;
00283     }
00284     memcpy( buffer + pos, argv[ i ], len );
00285     pos += len;
00286   }
00287   long env = 0;
00288   memcpy( buffer + pos, &env, sizeof( env ));
00289   pos += sizeof( env );
00290   long avoid_loops = 0;
00291   memcpy( buffer + pos, &avoid_loops, sizeof( avoid_loops ));
00292   pos += sizeof( avoid_loops );
00293   header.arg_length = pos;
00294   write_socket(socket, (char *) &header, sizeof(header));
00295   write_socket(socket, buffer, pos);
00296   if( read_socket( socket, (char *) &header, sizeof(header)) < 0
00297       || header.cmd != LAUNCHER_OK )
00298   {
00299     startDirectly( argv, argc );
00300     return;
00301   }
00302   long pid;
00303   read_socket(socket, buffer, header.arg_length);
00304   pid = *((long *) buffer);
00305 
00306   alarm(0); // Seems we made it....
00307 
00308   for(;;)
00309   {
00310     if( kill( pid, 0 ) < 0 )
00311       _exit(253);
00312     sleep(1);
00313     // the debugger should stop this process anyway
00314   }
00315 }
00316 
00317 // If we can't reach kdeinit we can still at least try to fork()
00318 void KCrash::startDirectly( const char* argv[], int )
00319 {
00320   fprintf( stderr, "KCrash cannot reach kdeinit, launching directly.\n" );
00321   pid_t pid = fork();
00322   if (pid <= 0)
00323   {
00324     if(!geteuid() && setgid(getgid()) < 0)
00325       _exit(253);
00326     if(!geteuid() && setuid(getuid()) < 0)
00327       _exit(253);
00328     execvp("drkonqi", const_cast< char** >( argv ));
00329     _exit(errno);
00330   }
00331   else
00332   {
00333     alarm(0); // Seems we made it....
00334     // wait for child to exit
00335     waitpid(pid, NULL, 0);
00336     _exit(253);
00337   }
00338 }
00339 
00340 // From now on this code is copy&pasted from kinit/wrapper.c :
00341 
00342 extern char **environ;
00343 
00344 static char *getDisplay()
00345 {
00346    const char *display;
00347    char *result;
00348    char *screen;
00349    char *colon;
00350    char *i;
00351 /*
00352  don't test for a value from qglobal.h but instead distinguish
00353  Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS
00354  on the commandline (which in qglobal.h however triggers Q_WS_QWS,
00355  but we don't want to include that here) (Simon)
00356 #ifdef Q_WS_X11
00357  */
00358 #if !defined(QWS)
00359    display = getenv("DISPLAY");
00360 #else
00361    display = getenv("QWS_DISPLAY");
00362 #endif
00363    if (!display || !*display)
00364    {
00365       display = ":0";
00366    }
00367    result = (char*)malloc(strlen(display)+1);
00368    if (result == NULL)
00369       return NULL;
00370 
00371    strcpy(result, display);
00372    screen = strrchr(result, '.');
00373    colon = strrchr(result, ':');
00374    if (screen && (screen > colon))
00375       *screen = '\0';
00376    while((i = strchr(result, ':')))
00377      *i = '_';
00378    return result;
00379 }
00380 
00381 /*
00382  * Write 'len' bytes from 'buffer' into 'sock'.
00383  * returns 0 on success, -1 on failure.
00384  */
00385 static int write_socket(int sock, char *buffer, int len)
00386 {
00387   ssize_t result;
00388   int bytes_left = len;
00389   while ( bytes_left > 0)
00390   {
00391      result = write(sock, buffer, bytes_left);
00392      if (result > 0)
00393      {
00394         buffer += result;
00395         bytes_left -= result;
00396      }
00397      else if (result == 0)
00398         return -1;
00399      else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
00400         return -1;
00401   }
00402   return 0;
00403 }
00404 
00405 /*
00406  * Read 'len' bytes from 'sock' into 'buffer'.
00407  * returns 0 on success, -1 on failure.
00408  */
00409 static int read_socket(int sock, char *buffer, int len)
00410 {
00411   ssize_t result;
00412   int bytes_left = len;
00413   while ( bytes_left > 0)
00414   {
00415      result = read(sock, buffer, bytes_left);
00416      if (result > 0)
00417      {
00418         buffer += result;
00419         bytes_left -= result;
00420      }
00421      else if (result == 0)
00422         return -1;
00423      else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
00424         return -1;
00425   }
00426   return 0;
00427 }
00428 
00429 static int openSocket()
00430 {
00431   kde_socklen_t socklen;
00432   int s;
00433   struct sockaddr_un server;
00434 #define MAX_SOCK_FILE 255
00435   char sock_file[MAX_SOCK_FILE + 1];
00436   const char *home_dir = getenv("HOME");
00437   const char *kde_home = getenv("KDEHOME");
00438   char *display;
00439 
00440   sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
00441 
00442   if (!kde_home || !kde_home[0])
00443   {
00444      kde_home = "~/.kde/";
00445   }
00446 
00447   if (kde_home[0] == '~')
00448   {
00449      if (!home_dir || !home_dir[0])
00450      {
00451         fprintf(stderr, "Warning: $HOME not set!\n");
00452         return -1;
00453      }
00454      if (strlen(home_dir) > (MAX_SOCK_FILE-100))
00455      {
00456         fprintf(stderr, "Warning: Home directory path too long!\n");
00457         return -1;
00458      }
00459      kde_home++;
00460      strncpy(sock_file, home_dir, MAX_SOCK_FILE);
00461   }
00462   strncat(sock_file, kde_home, MAX_SOCK_FILE - strlen(sock_file));
00463 
00465   if ( sock_file[strlen(sock_file)-1] == '/')
00466      sock_file[strlen(sock_file)-1] = 0;
00467   
00468   strncat(sock_file, "/socket-", MAX_SOCK_FILE - strlen(sock_file));
00469   if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
00470   {
00471      perror("Warning: Could not determine hostname: ");
00472      return -1;
00473   }
00474   sock_file[sizeof(sock_file)-1] = '\0';
00475 
00476   /* append $DISPLAY */
00477   display = getDisplay();
00478   if (display == NULL)
00479   {
00480      fprintf(stderr, "Error: Could not determine display.\n");
00481      return -1;
00482   }
00483 
00484   if (strlen(sock_file)+strlen(display)+strlen("/kdeinit_")+2 > MAX_SOCK_FILE)
00485   {
00486      fprintf(stderr, "Warning: Socket name will be too long.\n");
00487      free(display);
00488      return -1;
00489   }
00490   strcat(sock_file, "/kdeinit_");
00491   strcat(sock_file, display);
00492   free(display);
00493 
00494   if (strlen(sock_file) >= sizeof(server.sun_path))
00495   {
00496      fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
00497      return -1;
00498   }
00499 
00500   /*
00501    * create the socket stream
00502    */
00503   s = socket(PF_UNIX, SOCK_STREAM, 0);
00504   if (s < 0) 
00505   {
00506      perror("Warning: socket() failed: ");
00507      return -1;
00508   }
00509 
00510   server.sun_family = AF_UNIX;
00511   strcpy(server.sun_path, sock_file);
00512   socklen = sizeof(server);
00513   if(connect(s, (struct sockaddr *)&server, socklen) == -1) 
00514   {
00515      perror("Warning: connect() failed: ");
00516      close(s);
00517      return -1;
00518   }
00519   return s;
00520 }
00521 
00522 #endif // Q_OS_UNIX

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal