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());
215 kError() <<
"Could not find drkonqi";
236 #if defined(Q_OS_WIN) 237 static LPTOP_LEVEL_EXCEPTION_FILTER s_previousExceptionFilter = NULL;
239 if (handler && !s_previousExceptionFilter) {
241 }
else if (!handler && s_previousExceptionFilter) {
242 SetUnhandledExceptionFilter(s_previousExceptionFilter);
243 s_previousExceptionFilter = NULL;
253 signal (SIGSEGV, handler);
254 sigaddset(&mask, SIGSEGV);
257 signal (SIGBUS, handler);
258 sigaddset(&mask, SIGBUS);
261 signal (SIGFPE, handler);
262 sigaddset(&mask, SIGFPE);
265 signal (SIGILL, handler);
266 sigaddset(&mask, SIGILL);
269 signal (SIGABRT, handler);
270 sigaddset(&mask, SIGABRT);
273 sigprocmask(SIG_UNBLOCK, &mask, 0);
290 getrlimit(RLIMIT_NOFILE, &rlp);
291 for (
int i = 3; i < (int)rlp.rlim_cur; i++)
300 static int crashRecursionCounter = 0;
301 crashRecursionCounter++;
303 #if !defined(Q_OS_WIN) 304 signal(SIGALRM, SIG_DFL);
309 (void) printstack(2 );
312 if (crashRecursionCounter < 2) {
320 crashRecursionCounter++;
329 #if !defined(Q_OS_WIN) and !defined(Q_OS_MAC) 332 # if defined(Q_WS_X11) 333 else if (QX11Info::display())
334 close(ConnectionNumber(QX11Info::display()));
338 if (crashRecursionCounter < 3)
341 fprintf(stderr,
"KCrash: crashing... crashRecursionCounter = %d\n",
342 crashRecursionCounter);
343 fprintf(stderr,
"KCrash: Application Name = %s path = %s pid = %lld\n",
346 fprintf(stderr,
"KCrash: Arguments: ");
350 fprintf(stderr,
"\n");
352 fprintf(stderr,
"KCrash: Application '%s' crashing...\n",
353 s_appName ? s_appName :
"<unknown>");
358 #if !defined(Q_OS_WIN) 364 const char * argv[27];
372 argv[i++] =
"-display";
373 if ( QX11Info::display() )
374 argv[i++] = XDisplayString(QX11Info::display());
376 argv[i++] = getenv(
"DISPLAY");
377 #elif defined(Q_WS_QWS) 379 argv[i++] =
"-display";
380 argv[i++] = getenv(
"QWS_DISPLAY");
383 argv[i++] =
"--appname";
384 argv[i++] = s_appName ? s_appName :
"<unknown>";
387 argv[i++] =
"--kdeinit";
390 if (s_appPath && *s_appPath) {
391 argv[i++] =
"--apppath";
397 sprintf( sigtxt,
"%d", sig );
398 argv[i++] =
"--signal";
402 sprintf( pidtxt,
"%lld", QCoreApplication::applicationPid());
410 argv[i++] =
"--appversion";
415 argv[i++] =
"--programname";
420 argv[i++] =
"--bugaddress";
426 if (
kapp && !
kapp->startupId().isNull()) {
427 argv[i++] =
"--startupid";
428 strlcpy(sidtxt,
kapp->startupId().constData(),
sizeof(sidtxt));
433 argv[i++] =
"--safer";
436 argv[i++] =
"--restarted";
438 #if defined(Q_OS_WIN) 439 char threadId[8] = { 0 };
440 sprintf( threadId,
"%d", GetCurrentThreadId() );
441 argv[i++] =
"--thread";
442 argv[i++] = threadId;
451 if (crashRecursionCounter < 4)
453 fprintf(stderr,
"Unable to start Dr. Konqi\n");
459 #if defined(Q_OS_WIN) 464 for(
int i=0; i<argc; ++i) {
465 cmdLine.append(
'\"');
466 cmdLine.append(QFile::decodeName(argv[i]));
467 cmdLine.append(
"\" ");
470 PROCESS_INFORMATION procInfo;
471 STARTUPINFOW startupInfo = {
sizeof( STARTUPINFO ), 0, 0, 0,
472 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
473 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
476 bool success = CreateProcess(0, (
wchar_t*) cmdLine.utf16(), NULL, NULL,
477 false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL,
478 &startupInfo, &procInfo);
480 if (success && waitAndExit) {
482 WaitForSingleObject(procInfo.hProcess, INFINITE);
494 HANDLE hMapFile = NULL;
495 hMapFile = CreateFileMapping(
496 INVALID_HANDLE_VALUE,
501 TEXT(
"Local\\KCrashShared"));
504 pBuf = (LPCTSTR) MapViewOfFile(
510 CopyMemory((PVOID) pBuf, exceptionInfo->ContextRecord,
sizeof(CONTEXT));
516 CloseHandle(hMapFile);
517 return EXCEPTION_EXECUTE_HANDLER;
521 static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly);
522 static pid_t startFromKdeinit(
int argc,
const char *argv[]);
523 static pid_t startDirectly(
const char *argv[]);
524 static int write_socket(
int sock,
char *buffer,
int len);
525 static int read_socket(
int sock,
char *buffer,
int len);
526 static int openSocket();
530 bool startDirectly =
true;
539 startDirectly = !startProcessInternal(argc, argv, waitAndExit,
false);
545 startProcessInternal(argc, argv, waitAndExit,
true);
549 static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly)
551 fprintf(stderr,
"KCrash: Attempting to start %s %s\n", argv[0], directly ?
"directly" :
"from kdeinit");
553 pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv);
555 if (pid > 0 && waitAndExit) {
563 while(waitpid(-1, NULL, 0) != pid) {}
567 #ifndef PR_SET_PTRACER 568 # define PR_SET_PTRACER 0x59616d61 570 prctl(PR_SET_PTRACER, pid, 0, 0, 0);
573 while(kill(pid, 0) >= 0) {
583 static pid_t startFromKdeinit(
int argc,
const char *argv[])
585 int socket = openSocket();
589 header.cmd = LAUNCHER_EXEC_NEW;
590 const int BUFSIZE = 8192;
591 char buffer[ BUFSIZE + 10 ];
594 memcpy( buffer + pos, &argcl,
sizeof( argcl ));
595 pos +=
sizeof( argcl );
600 int len = strlen( argv[ i ] ) + 1;
601 if( pos + len >= BUFSIZE )
603 fprintf( stderr,
"BUFSIZE in KCrash not big enough!\n" );
606 memcpy( buffer + pos, argv[ i ], len );
610 memcpy( buffer + pos, &env,
sizeof( env ));
611 pos +=
sizeof( env );
612 long avoid_loops = 0;
613 memcpy( buffer + pos, &avoid_loops,
sizeof( avoid_loops ));
614 pos +=
sizeof( avoid_loops );
615 header.arg_length = pos;
616 write_socket(socket, (
char *) &header,
sizeof(header));
617 write_socket(socket, buffer, pos);
618 if( read_socket( socket, (
char *) &header,
sizeof(header)) < 0
619 || header.cmd != LAUNCHER_OK )
624 read_socket(socket, (
char *) &pid,
sizeof(pid));
625 return static_cast<pid_t
>(pid);
628 static pid_t startDirectly(
const char *argv[])
634 fprintf( stderr,
"KCrash failed to fork(), errno = %d\n", errno );
637 if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
640 execvp(argv[0], const_cast< char** >(argv));
641 fprintf( stderr,
"KCrash failed to exec(), errno = %d\n", errno );
650 static char *getDisplay()
665 display =
"NODISPLAY";
667 display = getenv(
"DISPLAY");
669 display = getenv(
"QWS_DISPLAY");
671 if (!display || !*display)
675 result = (
char*)malloc(strlen(display)+1);
679 strcpy(result, display);
680 screen = strrchr(result,
'.');
681 colon = strrchr(result,
':');
682 if (screen && (screen > colon))
684 while((i = strchr(result,
':')))
687 while((i = strchr(result,
'/')))
697 static int write_socket(
int sock,
char *buffer,
int len)
700 int bytes_left = len;
701 while ( bytes_left > 0)
703 result = write(sock, buffer, bytes_left);
707 bytes_left -= result;
709 else if (result == 0)
711 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
721 static int read_socket(
int sock,
char *buffer,
int len)
724 int bytes_left = len;
725 while ( bytes_left > 0)
727 result = read(sock, buffer, bytes_left);
731 bytes_left -= result;
733 else if (result == 0)
735 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
741 static int openSocket()
743 kde_socklen_t socklen;
745 struct sockaddr_un server;
746 #define MAX_SOCK_FILE 255 747 char sock_file[MAX_SOCK_FILE + 1];
748 const char *home_dir = getenv(
"HOME");
749 const char *kde_home = getenv(
"KDEHOME");
752 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
754 if (!kde_home || !kde_home[0])
756 kde_home =
"~/" KDE_DEFAULT_HOME
"/";
759 if (kde_home[0] ==
'~')
761 if (!home_dir || !home_dir[0])
763 fprintf(stderr,
"Warning: $HOME not set!\n");
766 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
768 fprintf(stderr,
"Warning: Home directory path too long!\n");
772 strlcpy(sock_file, home_dir, MAX_SOCK_FILE);
774 strlcat(sock_file, kde_home, MAX_SOCK_FILE);
777 if ( sock_file[strlen(sock_file)-1] ==
'/')
778 sock_file[strlen(sock_file)-1] = 0;
780 strlcat(sock_file,
"/socket-", MAX_SOCK_FILE);
781 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
783 perror(
"Warning: Could not determine hostname: ");
786 sock_file[
sizeof(sock_file)-1] =
'\0';
789 display = getDisplay();
792 fprintf(stderr,
"Error: Could not determine display.\n");
796 if (strlen(sock_file)+strlen(display)+strlen(
"/kdeinit4_")+2 > MAX_SOCK_FILE)
798 fprintf(stderr,
"Warning: Socket name will be too long.\n");
802 strcat(sock_file,
"/kdeinit4_");
803 strcat(sock_file, display);
806 if (strlen(sock_file) >=
sizeof(server.sun_path))
808 fprintf(stderr,
"Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
815 s = socket(PF_UNIX, SOCK_STREAM, 0);
818 perror(
"Warning: socket() failed: ");
822 server.sun_family = AF_UNIX;
823 strcpy(server.sun_path, sock_file);
825 fprintf(stderr,
"KCrash: Connect sock_file=%s\n", sock_file);
826 socklen =
sizeof(server);
827 if(connect(s, (
struct sockaddr *)&server, socklen) == -1)
829 perror(
"Warning: connect() failed: ");
static void closeAllFDs()
const KAboutData * aboutData() const
static QStringList allArguments()
QDebug perror(QDebug s, KDebugTag)
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
void startProcess(int argc, const char *argv[], bool waitAndExit)
This namespace contains functions to handle crashes.
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)
static char ** s_autoRestartCommandLine
static char * s_drkonqiPath
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.
void(* HandlerType)(int)
Typedef for a pointer to a crash handler function.
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.
const char * internalVersion() const
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
const char * internalProgramName() const
bool isSet(const QByteArray &option) const
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.
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.
const char * internalBugAddress() const
LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo)