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 sleep(1);
00313
00314 }
00315 }
00316
00317
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);
00334
00335 waitpid(pid, NULL, 0);
00336 _exit(253);
00337 }
00338 }
00339
00340
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
00353
00354
00355
00356
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
00383
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
00407
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
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
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