00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00067
00068
00069 void
00070 KCrash::setEmergencySaveFunction (HandlerType saveFunction)
00071 {
00072 _emergencySaveFunction = saveFunction;
00073
00074
00075
00076
00077
00078 if (_emergencySaveFunction && !_crashHandler)
00079 _crashHandler = defaultCrashHandler;
00080 }
00081
00082
00083
00084
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
00123
00124 static int crashRecursionCounter = 0;
00125 crashRecursionCounter++;
00126
00127 signal(SIGALRM, SIG_DFL);
00128 alarm(3);
00129
00130 if (crashRecursionCounter < 2) {
00131 if (_emergencySaveFunction) {
00132 _emergencySaveFunction (sig);
00133 }
00134 crashRecursionCounter++;
00135 }
00136
00137
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
00145
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];
00158 int i = 0;
00159
00160
00161 argv[i++] = "drkonqi";
00162
00163 #if defined Q_WS_X11
00164
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
00172 argv[i++] = "-display";
00173 argv[i++] = getenv("QWS_DISPLAY");
00174 #endif
00175
00176
00177 argv[i++] = "--appname";
00178 argv[i++] = appName;
00179 if (KApplication::loadedByKdeinit)
00180 argv[i++] = "--kdeinit";
00181
00182
00183 if (appPath) {
00184 argv[i++] = "--apppath";
00185 argv[i++] = appPath;
00186 }
00187
00188
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
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
00250
00251
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;
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;
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);
00307
00308 for(;;)
00309 {
00310 if( kill( pid, 0 ) < 0 )
00311 _exit(253);
00312 struct timeval tm;
00313 tm.tv_sec = 8;
00314 tm.tv_usec = 0;
00315 select(0, 0, 0, 0, &tm);
00316
00317 }
00318 }
00319
00320
00321 void KCrash::startDirectly( const char* argv[], int )
00322 {
00323 fprintf( stderr, "KCrash cannot reach kdeinit, launching directly.\n" );
00324 pid_t pid = fork();
00325 if (pid <= 0)
00326 {
00327 if(!geteuid() && setgid(getgid()) < 0)
00328 _exit(253);
00329 if(!geteuid() && setuid(getuid()) < 0)
00330 _exit(253);
00331 execvp("drkonqi", const_cast< char** >( argv ));
00332 _exit(errno);
00333 }
00334 else
00335 {
00336 alarm(0);
00337
00338 waitpid(pid, NULL, 0);
00339 _exit(253);
00340 }
00341 }
00342
00343
00344
00345 extern char **environ;
00346
00347 static char *getDisplay()
00348 {
00349 const char *display;
00350 char *result;
00351 char *screen;
00352 char *colon;
00353 char *i;
00354
00355
00356
00357
00358
00359
00360
00361 #if !defined(QWS)
00362 display = getenv("DISPLAY");
00363 #else
00364 display = getenv("QWS_DISPLAY");
00365 #endif
00366 if (!display || !*display)
00367 {
00368 display = ":0";
00369 }
00370 result = (char*)malloc(strlen(display)+1);
00371 if (result == NULL)
00372 return NULL;
00373
00374 strcpy(result, display);
00375 screen = strrchr(result, '.');
00376 colon = strrchr(result, ':');
00377 if (screen && (screen > colon))
00378 *screen = '\0';
00379 while((i = strchr(result, ':')))
00380 *i = '_';
00381 return result;
00382 }
00383
00384
00385
00386
00387
00388 static int write_socket(int sock, char *buffer, int len)
00389 {
00390 ssize_t result;
00391 int bytes_left = len;
00392 while ( bytes_left > 0)
00393 {
00394 result = write(sock, buffer, bytes_left);
00395 if (result > 0)
00396 {
00397 buffer += result;
00398 bytes_left -= result;
00399 }
00400 else if (result == 0)
00401 return -1;
00402 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
00403 return -1;
00404 }
00405 return 0;
00406 }
00407
00408
00409
00410
00411
00412 static int read_socket(int sock, char *buffer, int len)
00413 {
00414 ssize_t result;
00415 int bytes_left = len;
00416 while ( bytes_left > 0)
00417 {
00418 result = read(sock, buffer, bytes_left);
00419 if (result > 0)
00420 {
00421 buffer += result;
00422 bytes_left -= result;
00423 }
00424 else if (result == 0)
00425 return -1;
00426 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
00427 return -1;
00428 }
00429 return 0;
00430 }
00431
00432 static int openSocket()
00433 {
00434 kde_socklen_t socklen;
00435 int s;
00436 struct sockaddr_un server;
00437 #define MAX_SOCK_FILE 255
00438 char sock_file[MAX_SOCK_FILE + 1];
00439 const char *home_dir = getenv("HOME");
00440 const char *kde_home = getenv("KDEHOME");
00441 char *display;
00442
00443 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
00444
00445 if (!kde_home || !kde_home[0])
00446 {
00447 kde_home = "~/.kde/";
00448 }
00449
00450 if (kde_home[0] == '~')
00451 {
00452 if (!home_dir || !home_dir[0])
00453 {
00454 fprintf(stderr, "Warning: $HOME not set!\n");
00455 return -1;
00456 }
00457 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
00458 {
00459 fprintf(stderr, "Warning: Home directory path too long!\n");
00460 return -1;
00461 }
00462 kde_home++;
00463 strncpy(sock_file, home_dir, MAX_SOCK_FILE);
00464 }
00465 strncat(sock_file, kde_home, MAX_SOCK_FILE - strlen(sock_file));
00466
00468 if ( sock_file[strlen(sock_file)-1] == '/')
00469 sock_file[strlen(sock_file)-1] = 0;
00470
00471 strncat(sock_file, "/socket-", MAX_SOCK_FILE - strlen(sock_file));
00472 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
00473 {
00474 perror("Warning: Could not determine hostname: ");
00475 return -1;
00476 }
00477 sock_file[sizeof(sock_file)-1] = '\0';
00478
00479
00480 display = getDisplay();
00481 if (display == NULL)
00482 {
00483 fprintf(stderr, "Error: Could not determine display.\n");
00484 return -1;
00485 }
00486
00487 if (strlen(sock_file)+strlen(display)+strlen("/kdeinit_")+2 > MAX_SOCK_FILE)
00488 {
00489 fprintf(stderr, "Warning: Socket name will be too long.\n");
00490 free(display);
00491 return -1;
00492 }
00493 strcat(sock_file, "/kdeinit_");
00494 strcat(sock_file, display);
00495 free(display);
00496
00497 if (strlen(sock_file) >= sizeof(server.sun_path))
00498 {
00499 fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
00500 return -1;
00501 }
00502
00503
00504
00505
00506 s = socket(PF_UNIX, SOCK_STREAM, 0);
00507 if (s < 0)
00508 {
00509 perror("Warning: socket() failed: ");
00510 return -1;
00511 }
00512
00513 server.sun_family = AF_UNIX;
00514 strcpy(server.sun_path, sock_file);
00515 socklen = sizeof(server);
00516 if(connect(s, (struct sockaddr *)&server, socklen) == -1)
00517 {
00518 perror("Warning: connect() failed: ");
00519 close(s);
00520 return -1;
00521 }
00522 return s;
00523 }
00524
00525 #endif // Q_OS_UNIX