KDEUI
kcrash.cpp
Go to the documentation of this file.
00001 /* 00002 * This file is part of the KDE Libraries 00003 * Copyright (C) 2000 Timo Hummel <timo.hummel@sap.com> 00004 * Tom Braun <braunt@fh-konstanz.de> 00005 * Copyright 2009 KDE e.V. 00006 * By Adriaan de Groot <groot@kde.org> 00007 * Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com> 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Library General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Library General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Library General Public License 00020 * along with this library; see the file COPYING.LIB. If not, write to 00021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 * Boston, MA 02110-1301, USA. 00023 */ 00024 00025 #include "kcrash.h" 00026 #include <kcmdlineargs.h> 00027 #include <kstandarddirs.h> 00028 #include <config-kstandarddirs.h> 00029 00030 #include <config.h> 00031 00032 #include <string.h> 00033 #include <signal.h> 00034 #include <stdio.h> 00035 #include <stdlib.h> 00036 #include <unistd.h> 00037 00038 #include <sys/types.h> 00039 #include <sys/time.h> 00040 #include <sys/resource.h> 00041 #include <sys/wait.h> 00042 #include <sys/un.h> 00043 #include <sys/socket.h> 00044 #ifdef Q_OS_LINUX 00045 #include <sys/prctl.h> 00046 #endif 00047 #include <errno.h> 00048 00049 #include <qwindowdefs.h> 00050 #include <kglobal.h> 00051 #include <kcomponentdata.h> 00052 #include <kaboutdata.h> 00053 #include <kdebug.h> 00054 #include <kapplication.h> 00055 00056 #include <../kinit/klauncher_cmds.h> 00057 00058 #include <QtCore/QFileInfo> 00059 #include <QtCore/QDir> 00060 00061 #if defined Q_WS_X11 00062 #include <qx11info_x11.h> 00063 #include <X11/Xlib.h> 00064 #endif 00065 00066 #ifdef Q_OS_SOLARIS 00067 // Solaris has built-in, thread-safe, async-signal-safe, mechanisms 00068 // to walk the stack in the case of a crash, as well as (optionally) 00069 // to demangle C++ symbol names. In the case of a crash, dump a stack 00070 // trace to stderr before starting drKonqui (because what drKonqui is 00071 // going to do is -- through a complicated process -- print the 00072 // exact same information, but less reliably). 00073 #include <ucontext.h> 00074 #endif 00075 00076 #if defined(Q_OS_WIN) 00077 # include <windows.h> 00078 #endif 00079 00080 static KCrash::HandlerType s_emergencySaveFunction = 0; 00081 static KCrash::HandlerType s_crashHandler = 0; 00082 static char *s_appName = 0; 00083 static char *s_autoRestartCommand = 0; 00084 static char *s_appPath = 0; 00085 static int s_autoRestartArgc = 0; 00086 static char **s_autoRestartCommandLine = 0; 00087 static char *s_drkonqiPath = 0; 00088 static KCrash::CrashFlags s_flags = 0; 00089 static bool s_launchDrKonqi = false; 00090 00091 namespace KCrash 00092 { 00093 void startProcess(int argc, const char *argv[], bool waitAndExit); 00094 00095 #if defined(Q_OS_WIN) 00096 LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo); 00097 #endif 00098 } 00099 00100 void 00101 KCrash::setEmergencySaveFunction (HandlerType saveFunction) 00102 { 00103 s_emergencySaveFunction = saveFunction; 00104 00105 /* 00106 * We need at least the default crash handler for 00107 * emergencySaveFunction to be called 00108 */ 00109 if (s_emergencySaveFunction && !s_crashHandler) { 00110 setCrashHandler(defaultCrashHandler); 00111 } 00112 } 00113 00114 KCrash::HandlerType 00115 KCrash::emergencySaveFunction() 00116 { 00117 return s_emergencySaveFunction; 00118 } 00119 00120 // Set the default crash handler in 10 seconds 00121 // This is used after an autorestart, the second instance of the application 00122 // is started with --nocrashhandler (no drkonqi, more precisely), and we 00123 // set the defaultCrashHandler (to handle autorestart) after 10s. 00124 // The delay is to see if we stay up for more than 10s time, to avoid infinite 00125 // respawning if the app crashes on startup. 00126 class KCrashDelaySetHandler : public QObject 00127 { 00128 public: 00129 KCrashDelaySetHandler() { 00130 startTimer(10000); // 10 s 00131 } 00132 protected: 00133 void timerEvent(QTimerEvent *event) { 00134 if (!s_crashHandler) // not set meanwhile 00135 KCrash::setCrashHandler(KCrash::defaultCrashHandler); 00136 killTimer(event->timerId()); 00137 this->deleteLater(); 00138 } 00139 }; 00140 00141 00142 00143 void 00144 KCrash::setFlags(KCrash::CrashFlags flags) 00145 { 00146 s_flags = flags; 00147 if (s_flags & AutoRestart) { 00148 // We need at least the default crash handler for autorestart to work. 00149 if (!s_crashHandler) { 00150 KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde"); 00151 if (!args->isSet("crashhandler")) // --nocrashhandler was passed, probably due to a crash, delay restart handler 00152 new KCrashDelaySetHandler; 00153 else // probably because KDE_DEBUG=1. set restart handler immediately. 00154 setCrashHandler(defaultCrashHandler); 00155 } 00156 } 00157 } 00158 00159 //### KDE5:Consider merging the setApplicationPath and setApplicationName methods into one. 00160 void 00161 KCrash::setApplicationPath(const QString& path) 00162 { 00163 s_appPath = qstrdup(QFile::encodeName(path).constData()); 00164 00165 //if the appName has also been specified, update s_autoRestartCommand to be in the form "absolutePath/appName" 00166 if (s_appName) { 00167 delete[] s_autoRestartCommand; 00168 QFileInfo appExecutable(QDir(path), QFile::decodeName(s_appName)); 00169 QByteArray cmd = QFile::encodeName(appExecutable.absoluteFilePath()); 00170 s_autoRestartCommand = qstrdup(cmd.constData()); 00171 } 00172 00173 QStringList args = KCmdLineArgs::allArguments(); 00174 args[0] = s_autoRestartCommand; // replace argv[0] with full path above 00175 if (!args.contains("--nocrashhandler")) 00176 args.insert(1, "--nocrashhandler"); 00177 delete[] s_autoRestartCommandLine; 00178 s_autoRestartArgc = args.count(); 00179 s_autoRestartCommandLine = new char* [args.count() + 1]; 00180 for (int i = 0; i < args.count(); ++i) { 00181 s_autoRestartCommandLine[i] = qstrdup(QFile::encodeName(args.at(i)).constData()); 00182 } 00183 s_autoRestartCommandLine[args.count()] = 0; 00184 } 00185 00186 void 00187 KCrash::setApplicationName(const QString& name) 00188 { 00189 s_appName = qstrdup(QFile::encodeName(name).constData()); 00190 00191 //update the autoRestartCommand 00192 delete[] s_autoRestartCommand; 00193 if (s_appPath) { 00194 //if we have appPath, make autoRestartCommand be in the form "absolutePath/appName"... 00195 QFileInfo appExecutable(QDir(QFile::decodeName(s_appPath)), name); 00196 QByteArray cmd = QFile::encodeName(appExecutable.absoluteFilePath()); 00197 s_autoRestartCommand = qstrdup(cmd.constData()); 00198 } else { 00199 //...else just use the appName for the autoRestartCommand 00200 s_autoRestartCommand = qstrdup(s_appName); 00201 } 00202 } 00203 00204 void KCrash::setDrKonqiEnabled(bool enabled) 00205 { 00206 s_launchDrKonqi = enabled; 00207 if (s_launchDrKonqi && !s_drkonqiPath) { 00208 s_drkonqiPath = qstrdup(QFile::encodeName(KStandardDirs::findExe("drkonqi")).constData()); 00209 if (!s_drkonqiPath) { 00210 kError() << "Could not find drkonqi"; 00211 s_launchDrKonqi = false; 00212 } 00213 } 00214 00215 //we need at least the default crash handler to launch drkonqi 00216 if (s_launchDrKonqi && !s_crashHandler) { 00217 setCrashHandler(defaultCrashHandler); 00218 } 00219 } 00220 00221 bool KCrash::isDrKonqiEnabled() 00222 { 00223 return s_launchDrKonqi; 00224 } 00225 00226 void 00227 KCrash::setCrashHandler (HandlerType handler) 00228 { 00229 #if defined(Q_OS_WIN) 00230 static LPTOP_LEVEL_EXCEPTION_FILTER s_previousExceptionFilter = NULL; 00231 00232 if (handler && !s_previousExceptionFilter) { 00233 s_previousExceptionFilter = SetUnhandledExceptionFilter(KCrash::win32UnhandledExceptionFilter); 00234 } else if (!handler && s_previousExceptionFilter) { 00235 SetUnhandledExceptionFilter(s_previousExceptionFilter); 00236 s_previousExceptionFilter = NULL; 00237 } 00238 #else 00239 if (!handler) 00240 handler = SIG_DFL; 00241 00242 sigset_t mask; 00243 sigemptyset(&mask); 00244 00245 #ifdef SIGSEGV 00246 signal (SIGSEGV, handler); 00247 sigaddset(&mask, SIGSEGV); 00248 #endif 00249 #ifdef SIGBUS 00250 signal (SIGBUS, handler); 00251 sigaddset(&mask, SIGBUS); 00252 #endif 00253 #ifdef SIGFPE 00254 signal (SIGFPE, handler); 00255 sigaddset(&mask, SIGFPE); 00256 #endif 00257 #ifdef SIGILL 00258 signal (SIGILL, handler); 00259 sigaddset(&mask, SIGILL); 00260 #endif 00261 #ifdef SIGABRT 00262 signal (SIGABRT, handler); 00263 sigaddset(&mask, SIGABRT); 00264 #endif 00265 00266 sigprocmask(SIG_UNBLOCK, &mask, 0); 00267 #endif 00268 00269 s_crashHandler = handler; 00270 } 00271 00272 KCrash::HandlerType 00273 KCrash::crashHandler() 00274 { 00275 return s_crashHandler; 00276 } 00277 00278 static void 00279 closeAllFDs() 00280 { 00281 // Close all remaining file descriptors except for stdin/stdout/stderr 00282 struct rlimit rlp; 00283 getrlimit(RLIMIT_NOFILE, &rlp); 00284 for (int i = 3; i < (int)rlp.rlim_cur; i++) 00285 close(i); 00286 } 00287 00288 void 00289 KCrash::defaultCrashHandler (int sig) 00290 { 00291 // WABA: Do NOT use kDebug() in this function because it is much too risky! 00292 // Handle possible recursions 00293 static int crashRecursionCounter = 0; 00294 crashRecursionCounter++; // Nothing before this, please ! 00295 00296 #if !defined(Q_OS_WIN) 00297 signal(SIGALRM, SIG_DFL); 00298 alarm(3); // Kill me... (in case we deadlock in malloc) 00299 #endif 00300 00301 #ifdef Q_OS_SOLARIS 00302 (void) printstack(2 /* stderr, assuming it's still open. */); 00303 #endif 00304 00305 if (crashRecursionCounter < 2) { 00306 if (s_emergencySaveFunction) { 00307 s_emergencySaveFunction (sig); 00308 } 00309 if ((s_flags & AutoRestart) && s_autoRestartCommand) { 00310 sleep(1); 00311 startProcess(s_autoRestartArgc, const_cast<const char**>(s_autoRestartCommandLine), false); 00312 } 00313 crashRecursionCounter++; 00314 } 00315 00316 #if !defined(Q_OS_WIN) 00317 if (!(s_flags & KeepFDs)) 00318 closeAllFDs(); 00319 # if defined(Q_WS_X11) 00320 else if (QX11Info::display()) 00321 close(ConnectionNumber(QX11Info::display())); 00322 # endif 00323 #endif 00324 00325 if (crashRecursionCounter < 3) 00326 { 00327 #ifndef NDEBUG 00328 fprintf(stderr, "KCrash: crashing... crashRecursionCounter = %d\n", 00329 crashRecursionCounter); 00330 fprintf(stderr, "KCrash: Application Name = %s path = %s pid = %lld\n", 00331 s_appName ? s_appName : "<unknown>" , 00332 s_appPath ? s_appPath : "<unknown>", QCoreApplication::applicationPid()); 00333 fprintf(stderr, "KCrash: Arguments: "); 00334 for (int i = 0; s_autoRestartCommandLine[i]; ++i) { 00335 fprintf(stderr, "%s ", s_autoRestartCommandLine[i]); 00336 } 00337 fprintf(stderr, "\n"); 00338 #else 00339 fprintf(stderr, "KCrash: Application '%s' crashing...\n", 00340 s_appName ? s_appName : "<unknown>"); 00341 #endif 00342 00343 if (!s_launchDrKonqi) { 00344 setCrashHandler(0); 00345 #if !defined(Q_OS_WIN) 00346 raise(sig); // dump core, or whatever is the default action for this signal. 00347 #endif 00348 return; 00349 } 00350 00351 const char * argv[27]; // don't forget to update this 00352 int i = 0; 00353 00354 // argument 0 has to be drkonqi 00355 argv[i++] = s_drkonqiPath; 00356 00357 #if defined Q_WS_X11 00358 // start up on the correct display 00359 argv[i++] = "-display"; 00360 if ( QX11Info::display() ) 00361 argv[i++] = XDisplayString(QX11Info::display()); 00362 else 00363 argv[i++] = getenv("DISPLAY"); 00364 #elif defined(Q_WS_QWS) 00365 // start up on the correct display 00366 argv[i++] = "-display"; 00367 argv[i++] = getenv("QWS_DISPLAY"); 00368 #endif 00369 00370 argv[i++] = "--appname"; 00371 argv[i++] = s_appName ? s_appName : "<unknown>"; 00372 00373 if (KApplication::loadedByKdeinit) 00374 argv[i++] = "--kdeinit"; 00375 00376 // only add apppath if it's not NULL 00377 if (s_appPath && *s_appPath) { 00378 argv[i++] = "--apppath"; 00379 argv[i++] = s_appPath; 00380 } 00381 00382 // signal number -- will never be NULL 00383 char sigtxt[ 10 ]; 00384 sprintf( sigtxt, "%d", sig ); 00385 argv[i++] = "--signal"; 00386 argv[i++] = sigtxt; 00387 00388 char pidtxt[ 20 ]; 00389 sprintf( pidtxt, "%lld", QCoreApplication::applicationPid()); 00390 argv[i++] = "--pid"; 00391 argv[i++] = pidtxt; 00392 00393 const KComponentData componentData = KGlobal::mainComponent(); 00394 const KAboutData *about = componentData.isValid() ? componentData.aboutData() : 0; 00395 if (about) { 00396 if (about->internalVersion()) { 00397 argv[i++] = "--appversion"; 00398 argv[i++] = about->internalVersion(); 00399 } 00400 00401 if (about->internalProgramName()) { 00402 argv[i++] = "--programname"; 00403 argv[i++] = about->internalProgramName(); 00404 } 00405 00406 if (about->internalBugAddress()) { 00407 argv[i++] = "--bugaddress"; 00408 argv[i++] = about->internalBugAddress(); 00409 } 00410 } 00411 00412 char sidtxt[256]; 00413 if ( kapp && !kapp->startupId().isNull()) { 00414 argv[i++] = "--startupid"; 00415 strlcpy(sidtxt, kapp->startupId().constData(), sizeof(sidtxt)); 00416 argv[i++] = sidtxt; 00417 } 00418 00419 if ( s_flags & SaferDialog ) 00420 argv[i++] = "--safer"; 00421 00422 if ((s_flags & AutoRestart) && s_autoRestartCommand) 00423 argv[i++] = "--restarted"; //tell drkonqi if the app has been restarted 00424 00425 #if defined(Q_OS_WIN) 00426 char threadId[8] = { 0 }; 00427 sprintf( threadId, "%d", GetCurrentThreadId() ); 00428 argv[i++] = "--thread"; 00429 argv[i++] = threadId; 00430 #endif 00431 00432 // NULL terminated list 00433 argv[i] = NULL; 00434 00435 startProcess(i, argv, true); 00436 } 00437 00438 if (crashRecursionCounter < 4) 00439 { 00440 fprintf(stderr, "Unable to start Dr. Konqi\n"); 00441 } 00442 00443 _exit(255); 00444 } 00445 00446 #if defined(Q_OS_WIN) 00447 00448 void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit) 00449 { 00450 QString cmdLine; 00451 for(int i=0; i<argc; ++i) { 00452 cmdLine.append('\"'); 00453 cmdLine.append(QFile::decodeName(argv[i])); 00454 cmdLine.append("\" "); 00455 } 00456 00457 PROCESS_INFORMATION procInfo; 00458 STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0, 00459 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, 00460 (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, 00461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 00462 00463 bool success = CreateProcess(0, (wchar_t*) cmdLine.utf16(), NULL, NULL, 00464 false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL, 00465 &startupInfo, &procInfo); 00466 00467 if (success && waitAndExit) { 00468 // wait for child to exit 00469 WaitForSingleObject(procInfo.hProcess, INFINITE); 00470 _exit(253); 00471 } 00472 } 00473 00474 //glue function for calling the unix signal handler from the windows unhandled exception filter 00475 LONG WINAPI KCrash::win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo) 00476 { 00477 // kdbgwin needs the context inside exceptionInfo because if getting the context after the 00478 // exception happened, it will walk down the stack and will stop at KiUserEventDispatch in 00479 // ntdll.dll, which is supposed to dispatch the exception from kernel mode back to user mode 00480 // so... let's create some shared memory 00481 HANDLE hMapFile = NULL; 00482 hMapFile = CreateFileMapping( 00483 INVALID_HANDLE_VALUE, 00484 NULL, 00485 PAGE_READWRITE, 00486 0, 00487 sizeof(CONTEXT), 00488 TEXT("Local\\KCrashShared")); 00489 00490 LPCTSTR pBuf = NULL; 00491 pBuf = (LPCTSTR) MapViewOfFile( 00492 hMapFile, 00493 FILE_MAP_ALL_ACCESS, 00494 0, 00495 0, 00496 sizeof(CONTEXT)); 00497 CopyMemory((PVOID) pBuf, exceptionInfo->ContextRecord, sizeof(CONTEXT)); 00498 00499 if (s_crashHandler) { 00500 s_crashHandler(exceptionInfo->ExceptionRecord->ExceptionCode); 00501 } 00502 00503 CloseHandle(hMapFile); 00504 return EXCEPTION_EXECUTE_HANDLER; //allow windows to do the default action (terminate) 00505 } 00506 #else 00507 00508 static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly); 00509 static pid_t startFromKdeinit(int argc, const char *argv[]); 00510 static pid_t startDirectly(const char *argv[]); 00511 static int write_socket(int sock, char *buffer, int len); 00512 static int read_socket(int sock, char *buffer, int len); 00513 static int openSocket(); 00514 00515 void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit) 00516 { 00517 bool startDirectly = true; 00518 00519 // First try to start the app via kdeinit, if the AlwaysDirectly flag hasn't been specified. 00520 // This is done because it is dangerous to use fork() in the crash handler 00521 // (there can be functions registered to be performed before fork(), for example handling 00522 // of malloc locking, which doesn't work when malloc crashes because of heap corruption). 00523 if (!(s_flags & AlwaysDirectly)) { 00524 startDirectly = !startProcessInternal(argc, argv, waitAndExit, false); 00525 } 00526 00527 // If we can't reach kdeinit, we can still at least try to fork() 00528 if (startDirectly) { 00529 startProcessInternal(argc, argv, waitAndExit, true); 00530 } 00531 } 00532 00533 static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly) 00534 { 00535 fprintf(stderr, "KCrash: Attempting to start %s %s\n", argv[0], directly ? "directly" : "from kdeinit"); 00536 00537 pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv); 00538 00539 if (pid > 0 && waitAndExit) { 00540 // Seems we made it.... 00541 alarm(0); //stop the pending alarm that was set at the top of the defaultCrashHandler 00542 00543 // Wait forever until the started process exits. This code path is executed 00544 // when launching drkonqi. Note that drkonqi will stop this process in the meantime. 00545 if (directly) { 00546 //if the process was started directly, use waitpid(), as it's a child... 00547 while(waitpid(-1, NULL, 0) != pid) {} 00548 } else { 00549 #ifdef Q_OS_LINUX 00550 // Declare the process that will be debugging the crashed KDE app (#245529) 00551 #ifndef PR_SET_PTRACER 00552 # define PR_SET_PTRACER 0x59616d61 00553 #endif 00554 prctl(PR_SET_PTRACER, pid, 0, 0, 0); 00555 #endif 00556 //...else poll its status using kill() 00557 while(kill(pid, 0) >= 0) { 00558 sleep(1); 00559 } 00560 } 00561 _exit(253); 00562 } 00563 00564 return (pid > 0); //return true on success 00565 } 00566 00567 static pid_t startFromKdeinit(int argc, const char *argv[]) 00568 { 00569 int socket = openSocket(); 00570 if( socket < -1 ) 00571 return 0; 00572 klauncher_header header; 00573 header.cmd = LAUNCHER_EXEC_NEW; 00574 const int BUFSIZE = 8192; // make sure this is big enough 00575 char buffer[ BUFSIZE + 10 ]; 00576 int pos = 0; 00577 long argcl = argc; 00578 memcpy( buffer + pos, &argcl, sizeof( argcl )); 00579 pos += sizeof( argcl ); 00580 for( int i = 0; 00581 i < argc; 00582 ++i ) 00583 { 00584 int len = strlen( argv[ i ] ) + 1; // include terminating \0 00585 if( pos + len >= BUFSIZE ) 00586 { 00587 fprintf( stderr, "BUFSIZE in KCrash not big enough!\n" ); 00588 return 0; 00589 } 00590 memcpy( buffer + pos, argv[ i ], len ); 00591 pos += len; 00592 } 00593 long env = 0; 00594 memcpy( buffer + pos, &env, sizeof( env )); 00595 pos += sizeof( env ); 00596 long avoid_loops = 0; 00597 memcpy( buffer + pos, &avoid_loops, sizeof( avoid_loops )); 00598 pos += sizeof( avoid_loops ); 00599 header.arg_length = pos; 00600 write_socket(socket, (char *) &header, sizeof(header)); 00601 write_socket(socket, buffer, pos); 00602 if( read_socket( socket, (char *) &header, sizeof(header)) < 0 00603 || header.cmd != LAUNCHER_OK ) 00604 { 00605 return 0; 00606 } 00607 long pid; 00608 read_socket(socket, buffer, header.arg_length); 00609 pid = *((long *) buffer); 00610 return static_cast<pid_t>(pid); 00611 } 00612 00613 static pid_t startDirectly(const char *argv[]) 00614 { 00615 pid_t pid = fork(); 00616 switch (pid) 00617 { 00618 case -1: 00619 fprintf( stderr, "KCrash failed to fork(), errno = %d\n", errno ); 00620 return 0; 00621 case 0: 00622 if (setgid(getgid()) < 0 || setuid(getuid()) < 0) 00623 _exit(253); // This cannot happen. Theoretically. 00624 closeAllFDs(); // We are in the child now. Close FDs unconditionally. 00625 execvp(argv[0], const_cast< char** >(argv)); 00626 fprintf( stderr, "KCrash failed to exec(), errno = %d\n", errno ); 00627 _exit(253); 00628 default: 00629 return pid; 00630 } 00631 } 00632 00633 // From now on this code is copy&pasted from kinit/wrapper.c : 00634 00635 static char *getDisplay() 00636 { 00637 const char *display; 00638 char *result; 00639 char *screen; 00640 char *colon; 00641 char *i; 00642 /* 00643 don't test for a value from qglobal.h but instead distinguish 00644 Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS 00645 on the commandline (which in qglobal.h however triggers Q_WS_QWS, 00646 but we don't want to include that here) (Simon) 00647 #ifdef Q_WS_X11 00648 */ 00649 #ifdef NO_DISPLAY 00650 display = "NODISPLAY"; 00651 #elif !defined(QWS) 00652 display = getenv("DISPLAY"); 00653 #else 00654 display = getenv("QWS_DISPLAY"); 00655 #endif 00656 if (!display || !*display) 00657 { 00658 display = ":0"; 00659 } 00660 result = (char*)malloc(strlen(display)+1); 00661 if (result == NULL) 00662 return NULL; 00663 00664 strcpy(result, display); 00665 screen = strrchr(result, '.'); 00666 colon = strrchr(result, ':'); 00667 if (screen && (screen > colon)) 00668 *screen = '\0'; 00669 while((i = strchr(result, ':'))) 00670 *i = '_'; 00671 #ifdef __APPLE__ 00672 while((i = strchr(result, '/'))) 00673 *i = '_'; 00674 #endif 00675 return result; 00676 } 00677 00678 /* 00679 * Write 'len' bytes from 'buffer' into 'sock'. 00680 * returns 0 on success, -1 on failure. 00681 */ 00682 static int write_socket(int sock, char *buffer, int len) 00683 { 00684 ssize_t result; 00685 int bytes_left = len; 00686 while ( bytes_left > 0) 00687 { 00688 result = write(sock, buffer, bytes_left); 00689 if (result > 0) 00690 { 00691 buffer += result; 00692 bytes_left -= result; 00693 } 00694 else if (result == 0) 00695 return -1; 00696 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN)) 00697 return -1; 00698 } 00699 return 0; 00700 } 00701 00702 /* 00703 * Read 'len' bytes from 'sock' into 'buffer'. 00704 * returns 0 on success, -1 on failure. 00705 */ 00706 static int read_socket(int sock, char *buffer, int len) 00707 { 00708 ssize_t result; 00709 int bytes_left = len; 00710 while ( bytes_left > 0) 00711 { 00712 result = read(sock, buffer, bytes_left); 00713 if (result > 0) 00714 { 00715 buffer += result; 00716 bytes_left -= result; 00717 } 00718 else if (result == 0) 00719 return -1; 00720 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN)) 00721 return -1; 00722 } 00723 return 0; 00724 } 00725 00726 static int openSocket() 00727 { 00728 kde_socklen_t socklen; 00729 int s; 00730 struct sockaddr_un server; 00731 #define MAX_SOCK_FILE 255 00732 char sock_file[MAX_SOCK_FILE + 1]; 00733 const char *home_dir = getenv("HOME"); 00734 const char *kde_home = getenv("KDEHOME"); 00735 char *display; 00736 00737 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0; 00738 00739 if (!kde_home || !kde_home[0]) 00740 { 00741 kde_home = "~/" KDE_DEFAULT_HOME "/"; 00742 } 00743 00744 if (kde_home[0] == '~') 00745 { 00746 if (!home_dir || !home_dir[0]) 00747 { 00748 fprintf(stderr, "Warning: $HOME not set!\n"); 00749 return -1; 00750 } 00751 if (strlen(home_dir) > (MAX_SOCK_FILE-100)) 00752 { 00753 fprintf(stderr, "Warning: Home directory path too long!\n"); 00754 return -1; 00755 } 00756 kde_home++; 00757 strlcpy(sock_file, home_dir, MAX_SOCK_FILE); 00758 } 00759 strlcat(sock_file, kde_home, MAX_SOCK_FILE); 00760 00762 if ( sock_file[strlen(sock_file)-1] == '/') 00763 sock_file[strlen(sock_file)-1] = 0; 00764 00765 strlcat(sock_file, "/socket-", MAX_SOCK_FILE); 00766 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0) 00767 { 00768 perror("Warning: Could not determine hostname: "); 00769 return -1; 00770 } 00771 sock_file[sizeof(sock_file)-1] = '\0'; 00772 00773 /* append $DISPLAY */ 00774 display = getDisplay(); 00775 if (display == NULL) 00776 { 00777 fprintf(stderr, "Error: Could not determine display.\n"); 00778 return -1; 00779 } 00780 00781 if (strlen(sock_file)+strlen(display)+strlen("/kdeinit4_")+2 > MAX_SOCK_FILE) 00782 { 00783 fprintf(stderr, "Warning: Socket name will be too long.\n"); 00784 free(display); 00785 return -1; 00786 } 00787 strcat(sock_file, "/kdeinit4_"); 00788 strcat(sock_file, display); 00789 free(display); 00790 00791 if (strlen(sock_file) >= sizeof(server.sun_path)) 00792 { 00793 fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n"); 00794 return -1; 00795 } 00796 00797 /* 00798 * create the socket stream 00799 */ 00800 s = socket(PF_UNIX, SOCK_STREAM, 0); 00801 if (s < 0) 00802 { 00803 perror("Warning: socket() failed: "); 00804 return -1; 00805 } 00806 00807 server.sun_family = AF_UNIX; 00808 strcpy(server.sun_path, sock_file); 00809 printf("sock_file=%s\n", sock_file); 00810 socklen = sizeof(server); 00811 if(connect(s, (struct sockaddr *)&server, socklen) == -1) 00812 { 00813 perror("Warning: connect() failed: "); 00814 close(s); 00815 return -1; 00816 } 00817 return s; 00818 } 00819 00820 #endif // Q_OS_UNIX
KDE 4.6 API Reference