28 #include <config-kstandarddirs.h>
38 #include <sys/types.h>
40 #include <sys/resource.h>
43 #include <sys/socket.h>
45 #include <sys/prctl.h>
49 #include <qwindowdefs.h>
56 #include <../kinit/klauncher_cmds.h>
58 #include <QtCore/QFileInfo>
59 #include <QtCore/QDir>
62 #include <qx11info_x11.h>
93 void startProcess(
int argc,
const char *argv[],
bool waitAndExit);
126 class KCrashDelaySetHandler :
public QObject
129 KCrashDelaySetHandler() {
133 void timerEvent(QTimerEvent *event) {
136 killTimer(event->timerId());
151 if (!args->
isSet(
"crashhandler"))
152 new KCrashDelaySetHandler;
163 s_appPath = qstrdup(QFile::encodeName(path).constData());
168 QFileInfo appExecutable(QDir(path), QFile::decodeName(
s_appName));
169 QByteArray cmd = QFile::encodeName(appExecutable.absoluteFilePath());
175 if (!args.contains(
"--nocrashhandler"))
176 args.insert(1,
"--nocrashhandler");
180 for (
int i = 0; i < args.count(); ++i) {
189 s_appName = qstrdup(QFile::encodeName(name).constData());
195 QFileInfo appExecutable(QDir(QFile::decodeName(
s_appPath)), name);
196 QByteArray cmd = QFile::encodeName(appExecutable.absoluteFilePath());
206 s_launchDrKonqi = enabled;
210 kError() <<
"Could not find drkonqi";
211 s_launchDrKonqi =
false;
229 #if defined(Q_OS_WIN)
230 static LPTOP_LEVEL_EXCEPTION_FILTER s_previousExceptionFilter = NULL;
232 if (handler && !s_previousExceptionFilter) {
234 }
else if (!handler && s_previousExceptionFilter) {
235 SetUnhandledExceptionFilter(s_previousExceptionFilter);
236 s_previousExceptionFilter = NULL;
246 signal (SIGSEGV, handler);
247 sigaddset(&mask, SIGSEGV);
250 signal (SIGBUS, handler);
251 sigaddset(&mask, SIGBUS);
254 signal (SIGFPE, handler);
255 sigaddset(&mask, SIGFPE);
258 signal (SIGILL, handler);
259 sigaddset(&mask, SIGILL);
262 signal (SIGABRT, handler);
263 sigaddset(&mask, SIGABRT);
266 sigprocmask(SIG_UNBLOCK, &mask, 0);
283 getrlimit(RLIMIT_NOFILE, &rlp);
284 for (
int i = 3; i < (int)rlp.rlim_cur; i++)
293 static int crashRecursionCounter = 0;
294 crashRecursionCounter++;
296 #if !defined(Q_OS_WIN)
297 signal(SIGALRM, SIG_DFL);
302 (void) printstack(2 );
305 if (crashRecursionCounter < 2) {
313 crashRecursionCounter++;
316 #if !defined(Q_OS_WIN)
319 # if defined(Q_WS_X11)
320 else if (QX11Info::display())
321 close(ConnectionNumber(QX11Info::display()));
325 if (crashRecursionCounter < 3)
328 fprintf(stderr,
"KCrash: crashing... crashRecursionCounter = %d\n",
329 crashRecursionCounter);
330 fprintf(stderr,
"KCrash: Application Name = %s path = %s pid = %lld\n",
333 fprintf(stderr,
"KCrash: Arguments: ");
337 fprintf(stderr,
"\n");
339 fprintf(stderr,
"KCrash: Application '%s' crashing...\n",
340 s_appName ? s_appName :
"<unknown>");
343 if (!s_launchDrKonqi) {
345 #if !defined(Q_OS_WIN)
351 const char * argv[27];
359 argv[i++] =
"-display";
360 if ( QX11Info::display() )
361 argv[i++] = XDisplayString(QX11Info::display());
363 argv[i++] = getenv(
"DISPLAY");
364 #elif defined(Q_WS_QWS)
366 argv[i++] =
"-display";
367 argv[i++] = getenv(
"QWS_DISPLAY");
370 argv[i++] =
"--appname";
371 argv[i++] = s_appName ? s_appName :
"<unknown>";
374 argv[i++] =
"--kdeinit";
377 if (s_appPath && *s_appPath) {
378 argv[i++] =
"--apppath";
384 sprintf( sigtxt,
"%d", sig );
385 argv[i++] =
"--signal";
389 sprintf( pidtxt,
"%lld", QCoreApplication::applicationPid());
397 argv[i++] =
"--appversion";
402 argv[i++] =
"--programname";
407 argv[i++] =
"--bugaddress";
413 if (
kapp && !
kapp->startupId().isNull()) {
414 argv[i++] =
"--startupid";
415 strlcpy(sidtxt,
kapp->startupId().constData(),
sizeof(sidtxt));
420 argv[i++] =
"--safer";
423 argv[i++] =
"--restarted";
425 #if defined(Q_OS_WIN)
426 char threadId[8] = { 0 };
427 sprintf( threadId,
"%d", GetCurrentThreadId() );
428 argv[i++] =
"--thread";
429 argv[i++] = threadId;
438 if (crashRecursionCounter < 4)
440 fprintf(stderr,
"Unable to start Dr. Konqi\n");
446 #if defined(Q_OS_WIN)
451 for(
int i=0; i<argc; ++i) {
452 cmdLine.append(
'\"');
453 cmdLine.append(QFile::decodeName(argv[i]));
454 cmdLine.append(
"\" ");
457 PROCESS_INFORMATION procInfo;
458 STARTUPINFOW startupInfo = {
sizeof( STARTUPINFO ), 0, 0, 0,
459 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
460 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
463 bool success = CreateProcess(0, (
wchar_t*) cmdLine.utf16(), NULL, NULL,
464 false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL,
465 &startupInfo, &procInfo);
467 if (success && waitAndExit) {
469 WaitForSingleObject(procInfo.hProcess, INFINITE);
481 HANDLE hMapFile = NULL;
482 hMapFile = CreateFileMapping(
483 INVALID_HANDLE_VALUE,
488 TEXT(
"Local\\KCrashShared"));
491 pBuf = (LPCTSTR) MapViewOfFile(
497 CopyMemory((PVOID) pBuf, exceptionInfo->ContextRecord,
sizeof(CONTEXT));
503 CloseHandle(hMapFile);
504 return EXCEPTION_EXECUTE_HANDLER;
508 static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly);
509 static pid_t startFromKdeinit(
int argc,
const char *argv[]);
510 static pid_t startDirectly(
const char *argv[]);
511 static int write_socket(
int sock,
char *buffer,
int len);
512 static int read_socket(
int sock,
char *buffer,
int len);
513 static int openSocket();
517 bool startDirectly =
true;
524 startDirectly = !startProcessInternal(argc, argv, waitAndExit,
false);
529 startProcessInternal(argc, argv, waitAndExit,
true);
533 static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly)
535 fprintf(stderr,
"KCrash: Attempting to start %s %s\n", argv[0], directly ?
"directly" :
"from kdeinit");
537 pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv);
539 if (pid > 0 && waitAndExit) {
547 while(waitpid(-1, NULL, 0) != pid) {}
551 #ifndef PR_SET_PTRACER
552 # define PR_SET_PTRACER 0x59616d61
554 prctl(PR_SET_PTRACER, pid, 0, 0, 0);
557 while(kill(pid, 0) >= 0) {
567 static pid_t startFromKdeinit(
int argc,
const char *argv[])
569 int socket = openSocket();
573 header.cmd = LAUNCHER_EXEC_NEW;
574 const int BUFSIZE = 8192;
575 char buffer[ BUFSIZE + 10 ];
578 memcpy( buffer + pos, &argcl,
sizeof( argcl ));
579 pos +=
sizeof( argcl );
584 int len = strlen( argv[ i ] ) + 1;
585 if( pos + len >= BUFSIZE )
587 fprintf( stderr,
"BUFSIZE in KCrash not big enough!\n" );
590 memcpy( buffer + pos, argv[ i ], len );
594 memcpy( buffer + pos, &env,
sizeof( env ));
595 pos +=
sizeof( env );
596 long avoid_loops = 0;
597 memcpy( buffer + pos, &avoid_loops,
sizeof( avoid_loops ));
598 pos +=
sizeof( avoid_loops );
599 header.arg_length = pos;
600 write_socket(socket, (
char *) &header,
sizeof(header));
601 write_socket(socket, buffer, pos);
602 if( read_socket( socket, (
char *) &header,
sizeof(header)) < 0
603 || header.cmd != LAUNCHER_OK )
608 read_socket(socket, buffer, header.arg_length);
609 pid = *((
long *) buffer);
610 return static_cast<pid_t
>(pid);
613 static pid_t startDirectly(
const char *argv[])
619 fprintf( stderr,
"KCrash failed to fork(), errno = %d\n", errno );
622 if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
625 execvp(argv[0], const_cast< char** >(argv));
626 fprintf( stderr,
"KCrash failed to exec(), errno = %d\n", errno );
635 static char *getDisplay()
650 display =
"NODISPLAY";
652 display = getenv(
"DISPLAY");
654 display = getenv(
"QWS_DISPLAY");
656 if (!display || !*display)
660 result = (
char*)malloc(strlen(display)+1);
664 strcpy(result, display);
665 screen = strrchr(result,
'.');
666 colon = strrchr(result,
':');
667 if (screen && (screen > colon))
669 while((i = strchr(result,
':')))
672 while((i = strchr(result,
'/')))
682 static int write_socket(
int sock,
char *buffer,
int len)
685 int bytes_left = len;
686 while ( bytes_left > 0)
688 result = write(sock, buffer, bytes_left);
692 bytes_left -= result;
694 else if (result == 0)
696 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
706 static int read_socket(
int sock,
char *buffer,
int len)
709 int bytes_left = len;
710 while ( bytes_left > 0)
712 result = read(sock, buffer, bytes_left);
716 bytes_left -= result;
718 else if (result == 0)
720 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
726 static int openSocket()
728 kde_socklen_t socklen;
730 struct sockaddr_un server;
731 #define MAX_SOCK_FILE 255
732 char sock_file[MAX_SOCK_FILE + 1];
733 const char *home_dir = getenv(
"HOME");
734 const char *kde_home = getenv(
"KDEHOME");
737 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
739 if (!kde_home || !kde_home[0])
741 kde_home =
"~/" KDE_DEFAULT_HOME
"/";
744 if (kde_home[0] ==
'~')
746 if (!home_dir || !home_dir[0])
748 fprintf(stderr,
"Warning: $HOME not set!\n");
751 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
753 fprintf(stderr,
"Warning: Home directory path too long!\n");
757 strlcpy(sock_file, home_dir, MAX_SOCK_FILE);
759 strlcat(sock_file, kde_home, MAX_SOCK_FILE);
762 if ( sock_file[strlen(sock_file)-1] ==
'/')
763 sock_file[strlen(sock_file)-1] = 0;
765 strlcat(sock_file,
"/socket-", MAX_SOCK_FILE);
766 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
768 perror(
"Warning: Could not determine hostname: ");
771 sock_file[
sizeof(sock_file)-1] =
'\0';
774 display = getDisplay();
777 fprintf(stderr,
"Error: Could not determine display.\n");
781 if (strlen(sock_file)+strlen(display)+strlen(
"/kdeinit4_")+2 > MAX_SOCK_FILE)
783 fprintf(stderr,
"Warning: Socket name will be too long.\n");
787 strcat(sock_file,
"/kdeinit4_");
788 strcat(sock_file, display);
791 if (strlen(sock_file) >=
sizeof(server.sun_path))
793 fprintf(stderr,
"Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
800 s = socket(PF_UNIX, SOCK_STREAM, 0);
803 perror(
"Warning: socket() failed: ");
807 server.sun_family = AF_UNIX;
808 strcpy(server.sun_path, sock_file);
809 printf(
"sock_file=%s\n", sock_file);
810 socklen =
sizeof(server);
811 if(connect(s, (
struct sockaddr *)&server, socklen) == -1)
813 perror(
"Warning: connect() failed: ");