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, (
char *) &pid,
sizeof(pid));
609 return static_cast<pid_t
>(pid);
612 static pid_t startDirectly(
const char *argv[])
618 fprintf( stderr,
"KCrash failed to fork(), errno = %d\n", errno );
621 if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
624 execvp(argv[0], const_cast< char** >(argv));
625 fprintf( stderr,
"KCrash failed to exec(), errno = %d\n", errno );
634 static char *getDisplay()
649 display =
"NODISPLAY";
651 display = getenv(
"DISPLAY");
653 display = getenv(
"QWS_DISPLAY");
655 if (!display || !*display)
659 result = (
char*)malloc(strlen(display)+1);
663 strcpy(result, display);
664 screen = strrchr(result,
'.');
665 colon = strrchr(result,
':');
666 if (screen && (screen > colon))
668 while((i = strchr(result,
':')))
671 while((i = strchr(result,
'/')))
681 static int write_socket(
int sock,
char *buffer,
int len)
684 int bytes_left = len;
685 while ( bytes_left > 0)
687 result = write(sock, buffer, bytes_left);
691 bytes_left -= result;
693 else if (result == 0)
695 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
705 static int read_socket(
int sock,
char *buffer,
int len)
708 int bytes_left = len;
709 while ( bytes_left > 0)
711 result = read(sock, buffer, bytes_left);
715 bytes_left -= result;
717 else if (result == 0)
719 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
725 static int openSocket()
727 kde_socklen_t socklen;
729 struct sockaddr_un server;
730 #define MAX_SOCK_FILE 255
731 char sock_file[MAX_SOCK_FILE + 1];
732 const char *home_dir = getenv(
"HOME");
733 const char *kde_home = getenv(
"KDEHOME");
736 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
738 if (!kde_home || !kde_home[0])
740 kde_home =
"~/" KDE_DEFAULT_HOME
"/";
743 if (kde_home[0] ==
'~')
745 if (!home_dir || !home_dir[0])
747 fprintf(stderr,
"Warning: $HOME not set!\n");
750 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
752 fprintf(stderr,
"Warning: Home directory path too long!\n");
756 strlcpy(sock_file, home_dir, MAX_SOCK_FILE);
758 strlcat(sock_file, kde_home, MAX_SOCK_FILE);
761 if ( sock_file[strlen(sock_file)-1] ==
'/')
762 sock_file[strlen(sock_file)-1] = 0;
764 strlcat(sock_file,
"/socket-", MAX_SOCK_FILE);
765 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
767 perror(
"Warning: Could not determine hostname: ");
770 sock_file[
sizeof(sock_file)-1] =
'\0';
773 display = getDisplay();
776 fprintf(stderr,
"Error: Could not determine display.\n");
780 if (strlen(sock_file)+strlen(display)+strlen(
"/kdeinit4_")+2 > MAX_SOCK_FILE)
782 fprintf(stderr,
"Warning: Socket name will be too long.\n");
786 strcat(sock_file,
"/kdeinit4_");
787 strcat(sock_file, display);
790 if (strlen(sock_file) >=
sizeof(server.sun_path))
792 fprintf(stderr,
"Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
799 s = socket(PF_UNIX, SOCK_STREAM, 0);
802 perror(
"Warning: socket() failed: ");
806 server.sun_family = AF_UNIX;
807 strcpy(server.sun_path, sock_file);
808 printf(
"sock_file=%s\n", sock_file);
809 socklen =
sizeof(server);
810 if(connect(s, (
struct sockaddr *)&server, socklen) == -1)
812 perror(
"Warning: connect() failed: ");
static void closeAllFDs()
const char * internalVersion() const
static QStringList allArguments()
QDebug perror(QDebug s, KDebugTag)
void(* HandlerType)(int)
Typedef for a pointer to a crash handler function.
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
void startProcess(int argc, const char *argv[], bool waitAndExit)
const char * internalBugAddress() const
const char * name(StandardAction id)
This will return the internal name of a given standard action.
void defaultCrashHandler(int signal)
The default crash handler.
void setApplicationName(const QString &name)
Sets the application name which should be passed to DrKonqi, our nice crash display application...
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
const KAboutData * aboutData() const
static char ** s_autoRestartCommandLine
static char * s_drkonqiPath
bool isSet(const QByteArray &option) const
static int s_autoRestartArgc
void setApplicationPath(const QString &path)
Sets the application path which should be passed to DrKonqi, our nice crash display application...
static KCrash::HandlerType s_crashHandler
void setEmergencySaveFunction(HandlerType saveFunction=0)
Installs a function which should try to save the application's data.
don't close all file descriptors immediately
bool isDrKonqiEnabled()
Returns true if DrKonqi is set to be launched from the crash handler or false otherwise.
HandlerType emergencySaveFunction()
Returns the currently set emergency save function.
static KCrash::HandlerType s_emergencySaveFunction
autorestart this application. Only sensible for KUniqueApplications.
static bool s_launchDrKonqi
never try to to start DrKonqi via kdeinit. Use fork() and exec() instead.
start DrKonqi without arbitrary disk access
static char * s_autoRestartCommand
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
const KComponentData & mainComponent()
HandlerType crashHandler()
Returns the installed crash handler.
void setDrKonqiEnabled(bool enabled)
Enables or disables launching DrKonqi from the crash handler.
const char * internalProgramName() const
void setFlags(CrashFlags flags)
Set options to determine how the default crash handler should behave.
static KCrash::CrashFlags s_flags
static bool loadedByKdeinit
KAction * close(const QObject *recvr, const char *slot, QObject *parent)
Close the current document.
void setCrashHandler(HandlerType handler=defaultCrashHandler)
Install a function to be called when a crash occurs.
LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo)