28#include <config-kstandarddirs.h>
40#include <sys/resource.h>
43#include <sys/socket.h>
49#include <qwindowdefs.h>
56#include <../kinit/klauncher_cmds.h>
58#include <QtCore/QFileInfo>
62#include <qx11info_x11.h>
93 void startProcess(
int argc,
const char *argv[],
bool waitAndExit);
126class 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";
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",
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";
387 argv[i++] =
"--kdeinit";
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";
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");
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;
521static bool startProcessInternal(
int argc,
const char *argv[],
bool waitAndExit,
bool directly);
522static pid_t startFromKdeinit(
int argc,
const char *argv[]);
523static pid_t startDirectly(
const char *argv[]);
524static int write_socket(
int sock,
char *buffer,
int len);
525static int read_socket(
int sock,
char *buffer,
int len);
526static int openSocket();
530 bool startDirectly =
true;
538 if (!(
s_flags & AlwaysDirectly)) {
539 startDirectly = !startProcessInternal(argc, argv, waitAndExit,
false);
545 startProcessInternal(argc, argv, waitAndExit,
true);
549static 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) {
583static 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 );
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);
628static 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 );
650static 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,
'/')))
697static 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))
721static 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))
741static 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: ");
const char * internalBugAddress() const
const char * internalVersion() const
const char * internalProgramName() const
static bool loadedByKdeinit
bool isSet(const QByteArray &option) const
static QStringList allArguments()
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
const KAboutData * aboutData() const
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
static void closeAllFDs()
static KCrash::HandlerType s_emergencySaveFunction
static int s_autoRestartArgc
static char * s_drkonqiPath
static char * s_autoRestartCommand
static KCrash::HandlerType s_crashHandler
static KCrash::CrashFlags s_flags
static bool s_launchDrKonqi
static char ** s_autoRestartCommandLine
QDebug perror(QDebug s, KDebugTag)
This namespace contains functions to handle crashes.
void setCrashHandler(HandlerType handler=defaultCrashHandler)
Install a function to be called when a crash occurs.
HandlerType crashHandler()
Returns the installed crash handler.
void defaultCrashHandler(int signal)
The default crash handler.
void setApplicationPath(const QString &path)
Sets the application path which should be passed to DrKonqi, our nice crash display application.
void setDrKonqiEnabled(bool enabled)
Enables or disables launching DrKonqi from the crash handler.
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.
void setFlags(CrashFlags flags)
Set options to determine how the default crash handler should behave.
void setApplicationName(const QString &name)
Sets the application name which should be passed to DrKonqi, our nice crash display application.
HandlerType emergencySaveFunction()
Returns the currently set emergency save function.
void startProcess(int argc, const char *argv[], bool waitAndExit)
bool isDrKonqiEnabled()
Returns true if DrKonqi is set to be launched from the crash handler or false otherwise.
@ AutoRestart
autorestart this application. Only sensible for KUniqueApplications.
@ SaferDialog
start DrKonqi without arbitrary disk access
@ KeepFDs
don't close all file descriptors immediately
LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo)
const KComponentData & mainComponent()
KAction * close(const QObject *recvr, const char *slot, QObject *parent)
Close the current document.