• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal