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() {
151 if (!args->
isSet(
"crashhandler"))
152 new KCrashDelaySetHandler;
175 if (!args.
contains(
"--nocrashhandler"))
176 args.
insert(1,
"--nocrashhandler");
180 for (
int i = 0; i < args.
count(); ++i) {
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++;
322 #if !defined(Q_OS_WIN) and !defined(Q_OS_MAC)
325 # if defined(Q_WS_X11)
331 if (crashRecursionCounter < 3)
334 fprintf(stderr,
"KCrash: crashing... crashRecursionCounter = %d\n",
335 crashRecursionCounter);
336 fprintf(stderr,
"KCrash: Application Name = %s path = %s pid = %lld\n",
339 fprintf(stderr,
"KCrash: Arguments: ");
343 fprintf(stderr,
"\n");
345 fprintf(stderr,
"KCrash: Application '%s' crashing...\n",
346 s_appName ? s_appName :
"<unknown>");
349 if (!s_launchDrKonqi) {
351 #if !defined(Q_OS_WIN)
357 const char * argv[27];
365 argv[i++] =
"-display";
369 argv[i++] = getenv(
"DISPLAY");
370 #elif defined(Q_WS_QWS)
372 argv[i++] =
"-display";
373 argv[i++] = getenv(
"QWS_DISPLAY");
376 argv[i++] =
"--appname";
377 argv[i++] = s_appName ? s_appName :
"<unknown>";
380 argv[i++] =
"--kdeinit";
383 if (s_appPath && *s_appPath) {
384 argv[i++] =
"--apppath";
390 sprintf( sigtxt,
"%d", sig );
391 argv[i++] =
"--signal";
403 argv[i++] =
"--appversion";
408 argv[i++] =
"--programname";
413 argv[i++] =
"--bugaddress";
419 if (
kapp && !
kapp->startupId().isNull()) {
420 argv[i++] =
"--startupid";
421 strlcpy(sidtxt,
kapp->startupId().constData(),
sizeof(sidtxt));
426 argv[i++] =
"--safer";
429 argv[i++] =
"--restarted";
431 #if defined(Q_OS_WIN)
432 char threadId[8] = { 0 };
433 sprintf( threadId,
"%d", GetCurrentThreadId() );
434 argv[i++] =
"--thread";
435 argv[i++] = threadId;
444 if (crashRecursionCounter < 4)
446 fprintf(stderr,
"Unable to start Dr. Konqi\n");
452 #if defined(Q_OS_WIN)
457 for(
int i=0; i<argc; ++i) {
463 PROCESS_INFORMATION procInfo;
464 STARTUPINFOW startupInfo = {
sizeof( STARTUPINFO ), 0, 0, 0,
465 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
466 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
469 bool success = CreateProcess(0, (
wchar_t*) cmdLine.
utf16(), NULL, NULL,
470 false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL,
471 &startupInfo, &procInfo);
473 if (success && waitAndExit) {
475 WaitForSingleObject(procInfo.hProcess, INFINITE);
487 HANDLE hMapFile = NULL;
488 hMapFile = CreateFileMapping(
489 INVALID_HANDLE_VALUE,
494 TEXT(
"Local\\KCrashShared"));
497 pBuf = (LPCTSTR) MapViewOfFile(
503 CopyMemory((PVOID) pBuf, exceptionInfo->ContextRecord,
sizeof(CONTEXT));
509 CloseHandle(hMapFile);
510 return EXCEPTION_EXECUTE_HANDLER;
514 static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly);
515 static pid_t startFromKdeinit(
int argc,
const char *argv[]);
516 static pid_t startDirectly(
const char *argv[]);
517 static int write_socket(
int sock,
char *buffer,
int len);
518 static int read_socket(
int sock,
char *buffer,
int len);
519 static int openSocket();
523 bool startDirectly =
true;
532 startDirectly = !startProcessInternal(argc, argv, waitAndExit,
false);
538 startProcessInternal(argc, argv, waitAndExit,
true);
542 static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly)
544 fprintf(stderr,
"KCrash: Attempting to start %s %s\n", argv[0], directly ?
"directly" :
"from kdeinit");
546 pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv);
548 if (pid > 0 && waitAndExit) {
556 while(waitpid(-1, NULL, 0) != pid) {}
560 #ifndef PR_SET_PTRACER
561 # define PR_SET_PTRACER 0x59616d61
563 prctl(PR_SET_PTRACER, pid, 0, 0, 0);
566 while(kill(pid, 0) >= 0) {
576 static pid_t startFromKdeinit(
int argc,
const char *argv[])
578 int socket = openSocket();
582 header.cmd = LAUNCHER_EXEC_NEW;
583 const int BUFSIZE = 8192;
584 char buffer[ BUFSIZE + 10 ];
587 memcpy( buffer + pos, &argcl,
sizeof( argcl ));
588 pos +=
sizeof( argcl );
593 int len = strlen( argv[ i ] ) + 1;
594 if( pos + len >= BUFSIZE )
596 fprintf( stderr,
"BUFSIZE in KCrash not big enough!\n" );
599 memcpy( buffer + pos, argv[ i ], len );
603 memcpy( buffer + pos, &env,
sizeof( env ));
604 pos +=
sizeof( env );
605 long avoid_loops = 0;
606 memcpy( buffer + pos, &avoid_loops,
sizeof( avoid_loops ));
607 pos +=
sizeof( avoid_loops );
608 header.arg_length = pos;
609 write_socket(socket, (
char *) &header,
sizeof(header));
610 write_socket(socket, buffer, pos);
611 if( read_socket( socket, (
char *) &header,
sizeof(header)) < 0
612 || header.cmd != LAUNCHER_OK )
617 read_socket(socket, (
char *) &pid,
sizeof(pid));
618 return static_cast<pid_t
>(pid);
621 static pid_t startDirectly(
const char *argv[])
627 fprintf( stderr,
"KCrash failed to fork(), errno = %d\n", errno );
630 if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
633 execvp(argv[0], const_cast< char** >(argv));
634 fprintf( stderr,
"KCrash failed to exec(), errno = %d\n", errno );
643 static char *getDisplay()
658 display =
"NODISPLAY";
660 display = getenv(
"DISPLAY");
662 display = getenv(
"QWS_DISPLAY");
664 if (!display || !*display)
668 result = (
char*)malloc(strlen(display)+1);
672 strcpy(result, display);
673 screen = strrchr(result,
'.');
674 colon = strrchr(result,
':');
675 if (screen && (screen > colon))
677 while((i = strchr(result,
':')))
680 while((i = strchr(result,
'/')))
690 static int write_socket(
int sock,
char *buffer,
int len)
693 int bytes_left = len;
694 while ( bytes_left > 0)
696 result = write(sock, buffer, bytes_left);
700 bytes_left -= result;
702 else if (result == 0)
704 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
714 static int read_socket(
int sock,
char *buffer,
int len)
717 int bytes_left = len;
718 while ( bytes_left > 0)
720 result = read(sock, buffer, bytes_left);
724 bytes_left -= result;
726 else if (result == 0)
728 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
734 static int openSocket()
736 kde_socklen_t socklen;
738 struct sockaddr_un server;
739 #define MAX_SOCK_FILE 255
740 char sock_file[MAX_SOCK_FILE + 1];
741 const char *home_dir = getenv(
"HOME");
742 const char *kde_home = getenv(
"KDEHOME");
745 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
747 if (!kde_home || !kde_home[0])
749 kde_home =
"~/" KDE_DEFAULT_HOME
"/";
752 if (kde_home[0] ==
'~')
754 if (!home_dir || !home_dir[0])
756 fprintf(stderr,
"Warning: $HOME not set!\n");
759 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
761 fprintf(stderr,
"Warning: Home directory path too long!\n");
765 strlcpy(sock_file, home_dir, MAX_SOCK_FILE);
767 strlcat(sock_file, kde_home, MAX_SOCK_FILE);
770 if ( sock_file[strlen(sock_file)-1] ==
'/')
771 sock_file[strlen(sock_file)-1] = 0;
773 strlcat(sock_file,
"/socket-", MAX_SOCK_FILE);
774 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
776 perror(
"Warning: Could not determine hostname: ");
779 sock_file[
sizeof(sock_file)-1] =
'\0';
782 display = getDisplay();
785 fprintf(stderr,
"Error: Could not determine display.\n");
789 if (strlen(sock_file)+strlen(display)+strlen(
"/kdeinit4_")+2 > MAX_SOCK_FILE)
791 fprintf(stderr,
"Warning: Socket name will be too long.\n");
795 strcat(sock_file,
"/kdeinit4_");
796 strcat(sock_file, display);
799 if (strlen(sock_file) >=
sizeof(server.sun_path))
801 fprintf(stderr,
"Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
808 s = socket(PF_UNIX, SOCK_STREAM, 0);
811 perror(
"Warning: socket() failed: ");
815 server.sun_family = AF_UNIX;
816 strcpy(server.sun_path, sock_file);
818 fprintf(stderr,
"KCrash: Connect sock_file=%s\n", sock_file);
819 socklen =
sizeof(server);
820 if(connect(s, (
struct sockaddr *)&server, socklen) == -1)
822 perror(
"Warning: connect() failed: ");
static void closeAllFDs()
const char * internalVersion() const
static QStringList allArguments()
QString & append(QChar ch)
QDebug perror(QDebug s, KDebugTag)
void(* HandlerType)(int)
Typedef for a pointer to a crash handler function.
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
const T & at(int i) const
void startProcess(int argc, const char *argv[], bool waitAndExit)
bool contains(const QString &str, Qt::CaseSensitivity cs) const
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
virtual void timerEvent(QTimerEvent *event)
static char * s_drkonqiPath
bool isSet(const QByteArray &option) const
int count(const T &value) 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.
QString absoluteFilePath() const
const char * constData() const
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.
int startTimer(int interval)
static bool s_launchDrKonqi
const ushort * utf16() const
never try to to start DrKonqi via kdeinit. Use fork() and exec() instead.
start DrKonqi without arbitrary disk access
void insert(int i, const T &value)
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.
QByteArray encodeName(const QString &fileName)
QString decodeName(const QByteArray &localFileName)
void setCrashHandler(HandlerType handler=defaultCrashHandler)
Install a function to be called when a crash occurs.
LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo)