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