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

KInit

kinit.cpp

Go to the documentation of this file.
00001 /*
00002  * This file is part of the KDE libraries
00003  * Copyright (c) 1999-2000 Waldo Bastian <bastian@kde.org>
00004  *           (c) 1999 Mario Weilguni <mweilguni@sime.com>
00005  *           (c) 2001 Lubos Lunak <l.lunak@kde.org>
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Library General Public
00009  * License version 2 as published by the Free Software Foundation.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public License
00017  * along with this library; see the file COPYING.LIB.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  */
00021 
00022 #define QT_NO_CAST_FROM_ASCII
00023 
00024 #include <config.h>
00025 #include <config-kdeinit.h>
00026 
00027 #include <sys/types.h>
00028 #include <sys/time.h>
00029 #include <sys/resource.h>
00030 #include <sys/stat.h>
00031 #include <sys/socket.h>
00032 #include <sys/un.h>
00033 #include <sys/wait.h>
00034 #ifdef HAVE_SYS_SELECT_H
00035 #include <sys/select.h>     // Needed on some systems.
00036 #endif
00037 
00038 #include <ctype.h>
00039 #include <errno.h>
00040 #include <fcntl.h>
00041 #include "proctitle.h"
00042 #include <signal.h>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #include <locale.h>
00048 
00049 #include <QtCore/QLibrary>
00050 #include <QtCore/QString>
00051 #include <QtCore/QFile>
00052 #include <QtCore/QDate>
00053 #include <QtCore/QFileInfo>
00054 #include <QtCore/QRegExp>
00055 #include <QtGui/QFont>
00056 #include <kcomponentdata.h>
00057 #include <klibrary.h>
00058 #include <kdemacros.h>
00059 #include <kstandarddirs.h>
00060 #include <kglobalsettings.h>
00061 #include <kglobal.h>
00062 #include <kconfig.h>
00063 #include <kapplication.h>
00064 #include <klocale.h>
00065 #include <kdebug.h>
00066 #include <kde_file.h>
00067 #include <ksavefile.h>
00068 
00069 #ifdef Q_OS_LINUX
00070 #include <sys/prctl.h>
00071 #ifndef PR_SET_NAME
00072 #define PR_SET_NAME 15
00073 #endif
00074 #endif
00075 
00076 #ifdef Q_WS_MACX
00077 #include <kkernel_mac.h>
00078 #endif
00079 
00080 #include <kdeversion.h>
00081 
00082 #include "klauncher_cmds.h"
00083 
00084 #ifdef Q_WS_X11
00085 #include <X11/Xlib.h>
00086 #include <X11/Xatom.h>
00087 #include <fixx11h.h>
00088 #include <kstartupinfo.h>
00089 #endif
00090 
00091 #ifdef Q_WS_X11
00092 static const char *extra_libs[] = {
00093     "libkio.so.5",
00094     "libkparts.so.4",
00095 #ifdef __KDE_HAVE_GCC_VISIBILITY
00096     "libplasma.so.3"
00097 #endif
00098 };
00099 #endif
00100 
00101 // #define SKIP_PROCTITLE 1
00102 
00103 extern char **environ;
00104 
00105 #ifdef Q_WS_X11
00106 static int X11fd = -1;
00107 static Display *X11display = 0;
00108 static int X11_startup_notify_fd = -1;
00109 static Display *X11_startup_notify_display = 0;
00110 #endif
00111 static KComponentData *s_instance = 0;
00112 #define MAX_SOCK_FILE 255
00113 static char sock_file[MAX_SOCK_FILE];
00114 
00115 #ifdef Q_WS_X11
00116 #define DISPLAY "DISPLAY"
00117 #elif defined(Q_WS_QWS)
00118 #define DISPLAY "QWS_DISPLAY"
00119 #elif defined(Q_WS_MACX)
00120 #define DISPLAY "MAC_DISPLAY"
00121 #elif defined(Q_WS_WIN)
00122 #define DISPLAY "WIN_DISPLAY"
00123 #else
00124 #error Use QT/X11 or QT/Embedded
00125 #endif
00126 
00127 /* Group data */
00128 static struct {
00129   int maxname;
00130   int fd[2];
00131   int launcher[2]; /* socket pair for launcher communication */
00132   int deadpipe[2]; /* pipe used to detect dead children */
00133   int initpipe[2];
00134   int wrapper; /* socket for wrapper communication */
00135   int accepted_fd; /* socket accepted and that must be closed in the child process */
00136   char result;
00137   int exit_status;
00138   pid_t fork;
00139   pid_t launcher_pid;
00140   pid_t kded_pid;
00141   int n;
00142   char **argv;
00143   int (*func)(int, char *[]);
00144   int (*launcher_func)(int);
00145   bool debug_wait;
00146   QByteArray errorMsg;
00147   bool launcher_ok;
00148   bool suicide;
00149 } d;
00150 
00151 struct child
00152 {
00153   pid_t pid;
00154   int sock; /* fd to write message when child is dead*/
00155   struct child *next;
00156 };
00157 
00158 static struct child *children;
00159 
00160 #ifdef Q_WS_X11
00161 extern "C" {
00162 int kdeinit_xio_errhandler( Display * );
00163 int kdeinit_x_errhandler( Display *, XErrorEvent *err );
00164 }
00165 #endif
00166 
00167 #ifdef KDEINIT_OOM_PROTECT
00168 static int oom_pipe = -1;
00169 #endif
00170 
00171 /*
00172  * Clean up the file descriptor table by closing all file descriptors
00173  * that are still open.
00174  *
00175  * This function is called very early in the main() function, so that
00176  * we don't leak anything that was leaked to us.
00177  */
00178 static void cleanup_fds()
00179 {
00180     int maxfd = FD_SETSIZE;
00181     struct rlimit rl;
00182     if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
00183         maxfd = rl.rlim_max;
00184     for (int fd = 3; fd < maxfd; ++fd)
00185     {
00186 #ifdef KDEINIT_OOM_PROTECT
00187        if( fd != oom_pipe )
00188 #endif
00189           close(fd);
00190     }
00191 }
00192 
00193 /*
00194  * Close fd's which are only useful for the parent process.
00195  * Restore default signal handlers.
00196  */
00197 static void close_fds()
00198 {
00199    while (struct child *child = children) {
00200       close(child->sock);
00201       children = child->next;
00202       free(child);
00203    }
00204 
00205    if (d.deadpipe[0] != -1)
00206    {
00207       close(d.deadpipe[0]);
00208       d.deadpipe[0] = -1;
00209    }
00210 
00211    if (d.deadpipe[1] != -1)
00212    {
00213       close(d.deadpipe[1]);
00214       d.deadpipe[1] = -1;
00215    }
00216 
00217    if (d.initpipe[0] != -1)
00218    {
00219       close(d.initpipe[0]);
00220       d.initpipe[0] = -1;
00221    }
00222 
00223    if (d.initpipe[1] != -1)
00224    {
00225       close(d.initpipe[1]);
00226       d.initpipe[1] = -1;
00227    }
00228 
00229    if (d.launcher[0] != -1)
00230    {
00231       close(d.launcher[0]);
00232       d.launcher[0] = -1;
00233    }
00234    if (d.wrapper != -1)
00235    {
00236       close(d.wrapper);
00237       d.wrapper = -1;
00238    }
00239    if (d.accepted_fd != -1)
00240    {
00241       close(d.accepted_fd);
00242       d.accepted_fd = -1;
00243    }
00244 #ifdef Q_WS_X11
00245    if (X11fd >= 0)
00246    {
00247       close(X11fd);
00248       X11fd = -1;
00249    }
00250    if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd )
00251    {
00252       close(X11_startup_notify_fd);
00253       X11_startup_notify_fd = -1;
00254    }
00255 #endif
00256 
00257    KDE_signal(SIGCHLD, SIG_DFL);
00258    KDE_signal(SIGPIPE, SIG_DFL);
00259 }
00260 
00261 /* Notify wrapper program that the child it started has finished. */
00262 static void child_died(pid_t exit_pid, int exit_status)
00263 {
00264    struct child *child, **childptr = &children;
00265 
00266    while ((child = *childptr))
00267    {
00268       if (child->pid == exit_pid)
00269       {
00270          /* Send a message with the return value of the child on the control socket */
00271          klauncher_header request_header;
00272          long request_data[2];
00273          request_header.cmd = LAUNCHER_CHILD_DIED;
00274          request_header.arg_length = sizeof(long) * 2;
00275          request_data[0] = exit_pid;
00276          request_data[1] = exit_status;
00277          write(child->sock, &request_header, sizeof(request_header));
00278          write(child->sock, request_data, request_header.arg_length);
00279          close(child->sock);
00280 
00281          *childptr = child->next;
00282          free(child);
00283          return;
00284       }
00285 
00286       childptr = &child->next;
00287    }
00288 }
00289 
00290 
00291 static void exitWithErrorMsg(const QString &errorMsg)
00292 {
00293    fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() );
00294    QByteArray utf8ErrorMsg = errorMsg.toUtf8();
00295    d.result = 3; // Error with msg
00296    write(d.fd[1], &d.result, 1);
00297    int l = utf8ErrorMsg.length();
00298    write(d.fd[1], &l, sizeof(int));
00299    write(d.fd[1], utf8ErrorMsg.data(), l);
00300    close(d.fd[1]);
00301    exit(255);
00302 }
00303 
00304 static void setup_tty( const char* tty )
00305 {
00306     if( tty == NULL || *tty == '\0' )
00307         return;
00308     int fd = KDE_open( tty, O_WRONLY );
00309     if( fd < 0 )
00310     {
00311         perror( "kdeinit4: could not open() tty" );
00312         return;
00313     }
00314     if( dup2( fd, STDOUT_FILENO ) < 0 )
00315     {
00316         perror( "kdeinit4: could not dup2() stdout tty" );
00317     }
00318     if( dup2( fd, STDERR_FILENO ) < 0 )
00319     {
00320         perror( "kdeinit4: could not dup2() stderr tty" );
00321     }
00322     close( fd );
00323 }
00324 
00325 // from kdecore/netwm.cpp
00326 static int get_current_desktop( Display* disp )
00327 {
00328     int desktop = 0; // no desktop by default
00329 #ifdef Q_WS_X11 // Only X11 supports multiple desktops
00330     Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False );
00331     Atom type_ret;
00332     int format_ret;
00333     unsigned char *data_ret;
00334     unsigned long nitems_ret, unused;
00335     if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop,
00336         0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret )
00337         == Success)
00338     {
00339     if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1)
00340         desktop = *((long *) data_ret) + 1;
00341         if (data_ret)
00342             XFree ((char*) data_ret);
00343     }
00344 #endif
00345     return desktop;
00346 }
00347 
00348 // var has to be e.g. "DISPLAY=", i.e. with =
00349 const char* get_env_var( const char* var, int envc, const char* envs )
00350 {
00351     if( envc > 0 )
00352     { // get the var from envs
00353         const char* env_l = envs;
00354         int ln = strlen( var );
00355         for (int i = 0;  i < envc; i++)
00356         {
00357             if( strncmp( env_l, var, ln ) == 0 )
00358                 return env_l + ln;
00359             while(*env_l != 0) env_l++;
00360                 env_l++;
00361         }
00362     }
00363     return NULL;
00364 }
00365 
00366 #ifdef Q_WS_X11
00367 static void init_startup_info( KStartupInfoId& id, const char* bin,
00368     int envc, const char* envs )
00369 {
00370     const char* dpy = get_env_var( DISPLAY"=", envc, envs );
00371     // this may be called in a child, so it can't use display open using X11display
00372     // also needed for multihead
00373     X11_startup_notify_display = XOpenDisplay( dpy );
00374     if( X11_startup_notify_display == NULL )
00375         return;
00376     X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display );
00377     KStartupInfoData data;
00378     int desktop = get_current_desktop( X11_startup_notify_display );
00379     data.setDesktop( desktop );
00380     data.setBin(QFile::decodeName(bin));
00381     KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
00382     XFlush( X11_startup_notify_display );
00383 }
00384 
00385 static void complete_startup_info( KStartupInfoId& id, pid_t pid )
00386 {
00387     if( X11_startup_notify_display == NULL )
00388         return;
00389     if( pid == 0 ) // failure
00390         KStartupInfo::sendFinishX( X11_startup_notify_display, id );
00391     else
00392     {
00393         KStartupInfoData data;
00394         data.addPid( pid );
00395         data.setHostname();
00396         KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
00397     }
00398     XCloseDisplay( X11_startup_notify_display );
00399     X11_startup_notify_display = NULL;
00400     X11_startup_notify_fd = -1;
00401 }
00402 #endif
00403 
00404 QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops )
00405 {
00406      QStringList paths;
00407      const QRegExp pathSepRegExp(QString::fromLatin1("[:\b]"));
00408      if( envc > 0 ) /* use the passed environment */
00409      {
00410          const char* path = get_env_var( "PATH=", envc, envs );
00411          if( path != NULL )
00412              paths = QFile::decodeName(path).split(pathSepRegExp);
00413      } else {
00414          paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSepRegExp, QString::KeepEmptyParts);
00415      }
00416      QString execpath =
00417          s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":")));
00418      if (avoid_loops && !execpath.isEmpty()) {
00419          const int pos = execpath.lastIndexOf(QLatin1Char('/'));
00420          const QString bin_path = execpath.left(pos);
00421          for( QStringList::Iterator it = paths.begin();
00422               it != paths.end();
00423               ++it ) {
00424              if( *it == bin_path || *it == bin_path + QLatin1Char('/')) {
00425                  paths.erase( it );
00426                  break; // -->
00427              }
00428          }
00429          execpath = s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":")));
00430      }
00431      return QFile::encodeName(execpath);
00432 }
00433 
00434 #ifdef KDEINIT_OOM_PROTECT
00435 static void oom_protect_sighandler( int ) {
00436 }
00437 
00438 static void reset_oom_protect() {
00439    if( oom_pipe <= 0 )
00440       return;
00441    struct sigaction act, oldact;
00442    act.sa_handler = oom_protect_sighandler;
00443    act.sa_flags = 0;
00444    sigemptyset( &act.sa_mask );
00445    sigaction( SIGUSR1, &act, &oldact );
00446    sigset_t sigs, oldsigs;
00447    sigemptyset( &sigs );
00448    sigaddset( &sigs, SIGUSR1 );
00449    sigprocmask( SIG_BLOCK, &sigs, &oldsigs );
00450    pid_t pid = getpid();
00451    if( write( oom_pipe, &pid, sizeof( pid_t )) > 0 ) {
00452       sigsuspend( &oldsigs ); // wait for the signal to come
00453    } else {
00454 #ifndef NDEBUG
00455       fprintf( stderr, "Failed to reset OOM protection: %d\n", pid );
00456 #endif
00457    }
00458    sigprocmask( SIG_SETMASK, &oldsigs, NULL );
00459    sigaction( SIGUSR1, &oldact, NULL );
00460    close( oom_pipe );
00461    oom_pipe = -1;
00462 }
00463 #else
00464 static void reset_oom_protect() {
00465 }
00466 #endif
00467 
00468 static pid_t launch(int argc, const char *_name, const char *args,
00469                     const char *cwd=0, int envc=0, const char *envs=0,
00470                     bool reset_env = false,
00471                     const char *tty=0, bool avoid_loops = false,
00472                     const char* startup_id_str = "0" ) // krazy:exclude=doublequote_chars
00473 {
00474   QString lib;
00475   QByteArray name;
00476   QByteArray exec;
00477 
00478     QString libpath;
00479     QByteArray execpath;
00480     if (_name[0] != '/') {
00481         name = _name;
00482         lib = QFile::decodeName(name);
00483         exec = name;
00484         KLibrary klib(QLatin1String("libkdeinit4_") + lib, *s_instance );
00485         libpath = klib.fileName();
00486         if( libpath.isEmpty()) {
00487             KLibrary klib(lib, *s_instance);
00488             libpath = klib.fileName();
00489         }
00490         execpath = execpath_avoid_loops(exec, envc, envs, avoid_loops);
00491     } else {
00492         name = _name;
00493         lib = QFile::decodeName(name);
00494         name = name.mid(name.lastIndexOf('/') + 1);
00495         exec = _name;
00496         if (lib.endsWith(QLatin1String(".so")))
00497             libpath = lib;
00498         else {
00499             // try to match an absolute path to an executable binary (either in bin/ or in libexec/)
00500             // to a kdeinit module in the same prefix
00501             if( lib.contains( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ))) {
00502                 libpath = QString( lib ).replace( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ),
00503                     QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so");
00504             } else if( lib.contains( QLatin1String( "/bin/" ))) {
00505                 libpath = QString( lib ).replace( QLatin1String( "/bin/" ),
00506                     QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so");
00507             }
00508             // Don't confuse the user with "Could not load libkdeinit4_foo.so" if it doesn't exist
00509             if (!QFile::exists(libpath)) {
00510                 libpath.clear();
00511             }
00512             execpath = exec;
00513         }
00514     }
00515 #ifndef NDEBUG
00516     fprintf(stderr,"kdeinit4: preparing to launch %s\n", libpath.isEmpty()
00517         ? execpath.constData() : libpath.toUtf8().constData());
00518 #endif
00519     if (!args) {
00520         argc = 1;
00521     }
00522 
00523   if (0 > pipe(d.fd))
00524   {
00525      perror("kdeinit4: pipe() failed");
00526      d.result = 3;
00527      d.errorMsg = i18n("Unable to start new process.\n"
00528                        "The system may have reached the maximum number of open files possible or the maximum number of open files that you are allowed to use has been reached.").toUtf8();
00529      d.fork = 0;
00530      return d.fork;
00531   }
00532 
00533 #ifdef Q_WS_X11
00534   KStartupInfoId startup_id;
00535   startup_id.initId( startup_id_str );
00536   if( !startup_id.none())
00537       init_startup_info( startup_id, name, envc, envs );
00538 #endif
00539 
00540   d.errorMsg = 0;
00541   d.fork = fork();
00542   switch(d.fork) {
00543   case -1:
00544      perror("kdeinit4: fork() failed");
00545      d.result = 3;
00546      d.errorMsg = i18n("Unable to create new process.\n"
00547                        "The system may have reached the maximum number of processes possible or the maximum number of processes that you are allowed to use has been reached.").toUtf8();
00548      close(d.fd[0]);
00549      close(d.fd[1]);
00550      d.fork = 0;
00551      break;
00552   case 0:
00553   {
00555      close(d.fd[0]);
00556      close_fds();
00557      reset_oom_protect();
00558 
00559      // Try to chdir, either to the requested directory or to the user's document path by default.
00560      // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist,
00561      // we still want to execute `foo` even if the chdir() failed.
00562      if (cwd && *cwd) {
00563          (void)chdir(cwd);
00564      } else {
00565          // on Maemo5, documentPath() is on the SD card, setting it as working directory would block
00566          // USB mass storage access
00567 #ifndef Q_WS_MAEMO_5
00568          const QByteArray docPath = QFile::encodeName(KGlobalSettings::documentPath());
00569          (void)chdir(docPath.constData());
00570 #endif
00571      }
00572 
00573      if( reset_env ) // KWRAPPER/SHELL
00574      {
00575 
00576          QList<QByteArray> unset_envs;
00577          for( int tmp_env_count = 0;
00578               environ[tmp_env_count];
00579               tmp_env_count++)
00580              unset_envs.append( environ[ tmp_env_count ] );
00581          foreach(const QByteArray &tmp, unset_envs)
00582          {
00583              int pos = tmp.indexOf( '=' );
00584              if( pos >= 0 )
00585                  unsetenv( tmp.left( pos ));
00586          }
00587      }
00588 
00589      for (int i = 0;  i < envc; i++)
00590      {
00591         putenv((char *)envs);
00592         while(*envs != 0) envs++;
00593         envs++;
00594      }
00595 
00596 #ifdef Q_WS_X11
00597       if( startup_id.none())
00598           KStartupInfo::resetStartupEnv();
00599       else
00600           startup_id.setupStartupEnv();
00601 #endif
00602      {
00603        int r;
00604        QByteArray procTitle;
00605        d.argv = (char **) malloc(sizeof(char *) * (argc+1));
00606        d.argv[0] = (char *) _name;
00607 #ifdef Q_WS_MAC
00608        QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0]));
00609        if (!argvexe.isEmpty()) {
00610           QByteArray cstr = argvexe.toLocal8Bit();
00611           kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data();
00612           d.argv[0] = strdup(cstr.data());
00613        }
00614 #endif
00615        for (int i = 1;  i < argc; i++)
00616        {
00617           d.argv[i] = (char *) args;
00618           procTitle += ' ';
00619           procTitle += (char *) args;
00620           while(*args != 0) args++;
00621           args++;
00622        }
00623        d.argv[argc] = 0;
00624 
00625 #ifndef SKIP_PROCTITLE
00626 
00627 #ifdef Q_OS_LINUX
00628        /* set the process name, so that killall works like intended */
00629        r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0);
00630        if ( r == 0 )
00631            proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00632        else
00633            proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00634 #else
00635        proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00636 #endif
00637 #endif
00638      }
00639 
00640      if (libpath.isEmpty() && execpath.isEmpty())
00641      {
00642         QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name));
00643         exitWithErrorMsg(errorMsg);
00644      }
00645 
00646 
00647      if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty())
00648          libpath.truncate(0);
00649 
00650      QLibrary l(libpath);
00651 
00652      if ( !libpath.isEmpty() )
00653      {
00654        if (!l.load() || !l.isLoaded() )
00655        {
00656           QString ltdlError (l.errorString());
00657           if (execpath.isEmpty())
00658           {
00659              // Error
00660              QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError);
00661              exitWithErrorMsg(errorMsg);
00662           }
00663           else
00664           {
00665              // Print warning
00666              fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib),
00667                      qPrintable(ltdlError) );
00668           }
00669        }
00670      }
00671      if (!l.isLoaded())
00672      {
00673         d.result = 2; // Try execing
00674         write(d.fd[1], &d.result, 1);
00675 
00676         // We set the close on exec flag.
00677         // Closing of d.fd[1] indicates that the execvp succeeded!
00678         fcntl(d.fd[1], F_SETFD, FD_CLOEXEC);
00679 
00680         setup_tty( tty );
00681 
00682         QByteArray executable = execpath;
00683 #ifdef Q_WS_MAC
00684         QString bundlepath = s_instance->dirs()->findExe(QFile::decodeName(executable));
00685         if (!bundlepath.isEmpty())
00686            executable = QFile::encodeName(bundlepath);
00687 #endif
00688 
00689         if (!executable.isEmpty())
00690            execvp(executable, d.argv);
00691 
00692         d.result = 1; // Error
00693         write(d.fd[1], &d.result, 1);
00694         close(d.fd[1]);
00695         exit(255);
00696      }
00697 
00698      void * sym = l.resolve( "kdeinitmain");
00699      if (!sym )
00700         {
00701         sym = l.resolve( "kdemain" );
00702         if ( !sym )
00703            {
00704             QString ltdlError = l.errorString();
00705             fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) );
00706               QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2",
00707                                       libpath, ltdlError);
00708               exitWithErrorMsg(errorMsg);
00709            }
00710         }
00711 
00712      d.result = 0; // Success
00713      write(d.fd[1], &d.result, 1);
00714      close(d.fd[1]);
00715 
00716      d.func = (int (*)(int, char *[])) sym;
00717      if (d.debug_wait)
00718      {
00719         fprintf(stderr, "kdeinit4: Suspending process\n"
00720                         "kdeinit4: 'gdb kdeinit4 %d' to debug\n"
00721                         "kdeinit4: 'kill -SIGCONT %d' to continue\n",
00722                         getpid(), getpid());
00723         kill(getpid(), SIGSTOP);
00724      }
00725      else
00726      {
00727         setup_tty( tty );
00728      }
00729 
00730      exit( d.func(argc, d.argv)); /* Launch! */
00731 
00732      break;
00733   }
00734   default:
00736      close(d.fd[1]);
00737      bool exec = false;
00738      for(;;)
00739      {
00740        d.n = read(d.fd[0], &d.result, 1);
00741        if (d.n == 1)
00742        {
00743           if (d.result == 2)
00744           {
00745 #ifndef NDEBUG
00746              //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n");
00747 #endif
00748              exec = true;
00749              continue;
00750           }
00751           if (d.result == 3)
00752           {
00753              int l = 0;
00754              d.n = read(d.fd[0], &l, sizeof(int));
00755              if (d.n == sizeof(int))
00756              {
00757                 QByteArray tmp;
00758                 tmp.resize(l+1);
00759                 d.n = read(d.fd[0], tmp.data(), l);
00760                 tmp[l] = 0;
00761                 if (d.n == l)
00762                    d.errorMsg = tmp;
00763              }
00764           }
00765           // Finished
00766           break;
00767        }
00768        if (d.n == -1)
00769        {
00770           if (errno == ECHILD) {  // a child died.
00771              continue;
00772           }
00773           if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read
00774              continue;
00775           }
00776        }
00777        if (d.n == 0)
00778        {
00779           if (exec) {
00780              d.result = 0;
00781           } else {
00782              fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData());
00783              perror("kdeinit4: Pipe closed unexpectedly");
00784              d.result = 1; // Error
00785           }
00786           break;
00787        }
00788        perror("kdeinit4: Error reading from pipe");
00789        d.result = 1; // Error
00790        break;
00791      }
00792      close(d.fd[0]);
00793   }
00794 #ifdef Q_WS_X11
00795   if( !startup_id.none())
00796   {
00797      if( d.fork && d.result == 0 ) // launched successfully
00798         complete_startup_info( startup_id, d.fork );
00799      else // failure, cancel ASN
00800         complete_startup_info( startup_id, 0 );
00801   }
00802 #endif
00803   return d.fork;
00804 }
00805 
00806 extern "C" {
00807 
00808 static void sig_child_handler(int)
00809 {
00810    /*
00811     * Write into the pipe of death.
00812     * This way we are sure that we return from the select()
00813     *
00814     * A signal itself causes select to return as well, but
00815     * this creates a race-condition in case the signal arrives
00816     * just before we enter the select.
00817     */
00818    char c = 0;
00819    write(d.deadpipe[1], &c, 1);
00820 }
00821 
00822 }
00823 
00824 static void init_signals()
00825 {
00826   struct sigaction act;
00827   long options;
00828 
00829   if (pipe(d.deadpipe) != 0)
00830   {
00831      perror("kdeinit4: Aborting. Can not create pipe");
00832      exit(255);
00833   }
00834 
00835   options = fcntl(d.deadpipe[0], F_GETFL);
00836   if (options == -1)
00837   {
00838      perror("kdeinit4: Aborting. Can not make pipe non-blocking");
00839      exit(255);
00840   }
00841 
00842   if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1)
00843   {
00844      perror("kdeinit4: Aborting. Can not make pipe non-blocking");
00845      exit(255);
00846   }
00847 
00848   /*
00849    * A SIGCHLD handler is installed which sends a byte into the
00850    * pipe of death. This is to ensure that a dying child causes
00851    * an exit from select().
00852    */
00853   act.sa_handler=sig_child_handler;
00854   sigemptyset(&(act.sa_mask));
00855   sigaddset(&(act.sa_mask), SIGCHLD);
00856   sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00857   act.sa_flags = SA_NOCLDSTOP;
00858 
00859   // CC: take care of SunOS which automatically restarts interrupted system
00860   // calls (and thus does not have SA_RESTART)
00861 
00862 #ifdef SA_RESTART
00863   act.sa_flags |= SA_RESTART;
00864 #endif
00865   sigaction( SIGCHLD, &act, 0L);
00866 
00867   act.sa_handler=SIG_IGN;
00868   sigemptyset(&(act.sa_mask));
00869   sigaddset(&(act.sa_mask), SIGPIPE);
00870   sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00871   act.sa_flags = 0;
00872   sigaction( SIGPIPE, &act, 0L);
00873 }
00874 
00875 static void init_kdeinit_socket()
00876 {
00877   struct sockaddr_un sa;
00878   kde_socklen_t socklen;
00879   long options;
00880   const QByteArray home_dir = qgetenv("HOME");
00881   int max_tries = 10;
00882   if (home_dir.isEmpty())
00883   {
00884      fprintf(stderr, "kdeinit4: Aborting. $HOME not set!");
00885      exit(255);
00886   }
00887   if (chdir(home_dir) != 0) {
00888      fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData());
00889      exit(255);
00890   }
00891 
00892   {
00893      QByteArray path = home_dir;
00894      QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00895      if (access(path.data(), R_OK|W_OK))
00896      {
00897        if (errno == ENOENT)
00898        {
00899           fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data());
00900           exit(255);
00901        }
00902        else if (readOnly.isEmpty())
00903        {
00904           fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data());
00905           exit(255);
00906        }
00907      }
00908 #if 0 // obsolete in kde4. Should we check writing to another file instead?
00909      path = qgetenv("ICEAUTHORITY");
00910      if (path.isEmpty())
00911      {
00912         path = home_dir;
00913         path += "/.ICEauthority";
00914      }
00915      if (access(path.data(), R_OK|W_OK) && (errno != ENOENT))
00916      {
00917        fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data());
00918        exit(255);
00919      }
00920 #endif
00921   }
00922 
00927   if (access(sock_file, W_OK) == 0)
00928   {
00929      int s;
00930      struct sockaddr_un server;
00931 
00932 //     fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n");
00933      /*
00934       * create the socket stream
00935       */
00936      s = socket(PF_UNIX, SOCK_STREAM, 0);
00937      if (s < 0)
00938      {
00939         perror("socket() failed");
00940         exit(255);
00941      }
00942      server.sun_family = AF_UNIX;
00943      strcpy(server.sun_path, sock_file);
00944      socklen = sizeof(server);
00945 
00946      if(connect(s, (struct sockaddr *)&server, socklen) == 0)
00947      {
00948         fprintf(stderr, "kdeinit4: Shutting down running client.\n");
00949         klauncher_header request_header;
00950         request_header.cmd = LAUNCHER_TERMINATE_KDEINIT;
00951         request_header.arg_length = 0;
00952         write(s, &request_header, sizeof(request_header));
00953         sleep(1); // Give it some time
00954      }
00955      close(s);
00956   }
00957 
00959   unlink(sock_file);
00960 
00962   d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0);
00963   if (d.wrapper < 0)
00964   {
00965      perror("kdeinit4: Aborting. socket() failed");
00966      exit(255);
00967   }
00968 
00969   options = fcntl(d.wrapper, F_GETFL);
00970   if (options == -1)
00971   {
00972      perror("kdeinit4: Aborting. Can not make socket non-blocking");
00973      close(d.wrapper);
00974      exit(255);
00975   }
00976 
00977   if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1)
00978   {
00979      perror("kdeinit4: Aborting. Can not make socket non-blocking");
00980      close(d.wrapper);
00981      exit(255);
00982   }
00983 
00984   while (1) {
00986       socklen = sizeof(sa);
00987       memset(&sa, 0, socklen);
00988       sa.sun_family = AF_UNIX;
00989       strcpy(sa.sun_path, sock_file);
00990       if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0)
00991       {
00992           if (max_tries == 0) {
00993           perror("kdeinit4: Aborting. bind() failed");
00994           fprintf(stderr, "Could not bind to socket '%s'\n", sock_file);
00995           close(d.wrapper);
00996           exit(255);
00997       }
00998       max_tries--;
00999       } else
01000           break;
01001   }
01002 
01004   if (chmod(sock_file, 0600) != 0)
01005   {
01006      perror("kdeinit4: Aborting. Can not set permissions on socket");
01007      fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
01008      unlink(sock_file);
01009      close(d.wrapper);
01010      exit(255);
01011   }
01012 
01013   if(listen(d.wrapper, SOMAXCONN) < 0)
01014   {
01015      perror("kdeinit4: Aborting. listen() failed");
01016      unlink(sock_file);
01017      close(d.wrapper);
01018      exit(255);
01019   }
01020 }
01021 
01022 /*
01023  * Read 'len' bytes from 'sock' into buffer.
01024  * returns 0 on success, -1 on failure.
01025  */
01026 static int read_socket(int sock, char *buffer, int len)
01027 {
01028   ssize_t result;
01029   int bytes_left = len;
01030   while ( bytes_left > 0)
01031   {
01032      result = read(sock, buffer, bytes_left);
01033      if (result > 0)
01034      {
01035         buffer += result;
01036         bytes_left -= result;
01037      }
01038      else if (result == 0)
01039         return -1;
01040      else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
01041         return -1;
01042   }
01043   return 0;
01044 }
01045 
01046 static void start_klauncher()
01047 {
01048     if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) {
01049         perror("kdeinit4: socketpair() failed");
01050         exit(255);
01051     }
01052     char args[32];
01053     strcpy(args, "--fd=");
01054     sprintf(args + 5, "%d", d.launcher[1]);
01055     d.launcher_pid = launch( 2, "klauncher", args );
01056     close(d.launcher[1]);
01057 #ifndef NDEBUG
01058     fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n",
01059                     (long) d.launcher_pid, d.result);
01060 #endif
01061 }
01062 
01063 static void launcher_died()
01064 {
01065    if (!d.launcher_ok)
01066    {
01067       /* This is bad. */
01068       fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
01069       ::exit(255);
01070       return;
01071    }
01072 
01073    // KLauncher died... restart
01074 #ifndef NDEBUG
01075    fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
01076 #endif
01077    // Make sure it's really dead.
01078    if (d.launcher_pid)
01079    {
01080       kill(d.launcher_pid, SIGKILL);
01081       sleep(1); // Give it some time
01082    }
01083 
01084    d.launcher_ok = false;
01085    d.launcher_pid = 0;
01086    close(d.launcher[0]);
01087    d.launcher[0] = -1;
01088 
01089    start_klauncher();
01090 }
01091 
01092 static bool handle_launcher_request(int sock, const char *who)
01093 {
01094    (void)who; // for NDEBUG
01095 
01096    klauncher_header request_header;
01097    char *request_data = 0L;
01098    int result = read_socket(sock, (char *) &request_header, sizeof(request_header));
01099    if (result != 0)
01100    {
01101       return false;
01102    }
01103 
01104    if ( request_header.arg_length != 0 )
01105    {
01106        request_data = (char *) malloc(request_header.arg_length);
01107 
01108        result = read_socket(sock, request_data, request_header.arg_length);
01109        if (result != 0)
01110        {
01111            free(request_data);
01112            return false;
01113        }
01114    }
01115 
01116    //kDebug() << "Got cmd" << request_header.cmd << commandToString(request_header.cmd);
01117    if (request_header.cmd == LAUNCHER_OK)
01118    {
01119       d.launcher_ok = true;
01120    }
01121    else if (request_header.arg_length &&
01122       ((request_header.cmd == LAUNCHER_EXEC) ||
01123        (request_header.cmd == LAUNCHER_EXT_EXEC) ||
01124        (request_header.cmd == LAUNCHER_SHELL ) ||
01125        (request_header.cmd == LAUNCHER_KWRAPPER) ||
01126        (request_header.cmd == LAUNCHER_EXEC_NEW)))
01127    {
01128       pid_t pid;
01129       klauncher_header response_header;
01130       long response_data;
01131       long l;
01132       memcpy( &l, request_data, sizeof( long ));
01133       int argc = l;
01134       const char *name = request_data + sizeof(long);
01135       const char *args = name + strlen(name) + 1;
01136       const char *cwd = 0;
01137       int envc = 0;
01138       const char *envs = 0;
01139       const char *tty = 0;
01140       int avoid_loops = 0;
01141       const char *startup_id_str = "0"; // krazy:exclude=doublequote_chars
01142 
01143 #ifndef NDEBUG
01144      fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n",
01145              commandToString(request_header.cmd),
01146              name, who);
01147 #endif
01148 
01149       const char *arg_n = args;
01150       for(int i = 1; i < argc; i++)
01151       {
01152         arg_n = arg_n + strlen(arg_n) + 1;
01153       }
01154 
01155       if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER )
01156       {
01157          // Shell or kwrapper
01158          cwd = arg_n; arg_n += strlen(cwd) + 1;
01159       }
01160       if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01161           || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01162       {
01163          memcpy( &l, arg_n, sizeof( long ));
01164          envc = l;
01165          arg_n += sizeof(long);
01166          envs = arg_n;
01167          for(int i = 0; i < envc; i++)
01168          {
01169            arg_n = arg_n + strlen(arg_n) + 1;
01170          }
01171          if( request_header.cmd == LAUNCHER_KWRAPPER )
01172          {
01173              tty = arg_n;
01174              arg_n += strlen( tty ) + 1;
01175          }
01176       }
01177 
01178      if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01179          || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01180      {
01181          memcpy( &l, arg_n, sizeof( long ));
01182          avoid_loops = l;
01183          arg_n += sizeof( long );
01184      }
01185 
01186      if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01187          || request_header.cmd == LAUNCHER_EXT_EXEC )
01188      {
01189          startup_id_str = arg_n;
01190          arg_n += strlen( startup_id_str ) + 1;
01191      }
01192 
01193      if ((request_header.arg_length > (arg_n - request_data)) &&
01194          (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ))
01195      {
01196          // Optional cwd
01197          cwd = arg_n; arg_n += strlen(cwd) + 1;
01198      }
01199 
01200      if ((arg_n - request_data) != request_header.arg_length)
01201      {
01202 #ifndef NDEBUG
01203        fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n");
01204 #endif
01205        free(request_data);
01206        d.debug_wait = false;
01207        return true; // sure?
01208      }
01209 
01210       // support for the old a bit broken way of setting DISPLAY for multihead
01211       QByteArray olddisplay = qgetenv(DISPLAY);
01212       QByteArray kdedisplay = qgetenv("KDE_DISPLAY");
01213       bool reset_display = (! olddisplay.isEmpty() &&
01214                             ! kdedisplay.isEmpty() &&
01215                             olddisplay != kdedisplay);
01216 
01217       if (reset_display)
01218           setenv(DISPLAY, kdedisplay, true);
01219 
01220       pid = launch( argc, name, args, cwd, envc, envs,
01221           request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER,
01222           tty, avoid_loops, startup_id_str );
01223 
01224       if (reset_display) {
01225           unsetenv("KDE_DISPLAY");
01226           setenv(DISPLAY, olddisplay, true);
01227       }
01228 
01229       if (pid && (d.result == 0))
01230       {
01231          response_header.cmd = LAUNCHER_OK;
01232          response_header.arg_length = sizeof(response_data);
01233          response_data = pid;
01234          write(sock, &response_header, sizeof(response_header));
01235          write(sock, &response_data, response_header.arg_length);
01236 
01237          /* add new child to list */
01238          struct child *child = (struct child *) malloc(sizeof(struct child));
01239          child->pid = pid;
01240          child->sock = dup(sock);
01241          child->next = children;
01242          children = child;
01243       }
01244       else
01245       {
01246          int l = d.errorMsg.length();
01247          if (l) l++; // Include trailing null.
01248          response_header.cmd = LAUNCHER_ERROR;
01249          response_header.arg_length = l;
01250          write(sock, &response_header, sizeof(response_header));
01251          if (l)
01252             write(sock, d.errorMsg.data(), l);
01253       }
01254       d.debug_wait = false;
01255    }
01256    else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV)
01257    {
01258       const char *env_name;
01259       const char *env_value;
01260       env_name = request_data;
01261       env_value = env_name + strlen(env_name) + 1;
01262 
01263 #ifndef NDEBUG
01264       fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who);
01265 #endif
01266 
01267       if ( request_header.arg_length !=
01268           (int) (strlen(env_name) + strlen(env_value) + 2))
01269       {
01270 #ifndef NDEBUG
01271          fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n");
01272 #endif
01273          free(request_data);
01274          return true; // sure?
01275       }
01276       setenv( env_name, env_value, 1);
01277    }
01278    else if (request_header.cmd == LAUNCHER_TERMINATE_KDE)
01279    {
01280 #ifndef NDEBUG
01281        fprintf(stderr,"kdeinit4: terminate KDE.\n");
01282 #endif
01283 #ifdef Q_WS_X11
01284        kdeinit_xio_errhandler( 0L );
01285 #endif
01286    }
01287    else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT)
01288    {
01289 #ifndef NDEBUG
01290       fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid());
01291 #endif
01292       if (d.launcher_pid) {
01293          kill(d.launcher_pid, SIGTERM);
01294          d.launcher_pid = 0;
01295          close(d.launcher[0]);
01296          d.launcher[0] = -1;
01297       }
01298       unlink(sock_file);
01299       if (children) {
01300          close(d.wrapper);
01301          d.wrapper = -1;
01302 #ifndef NDEBUG
01303          fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n");
01304 #endif
01305       } else {
01306          raise(SIGTERM);
01307       }
01308    }
01309    else if (request_header.cmd == LAUNCHER_DEBUG_WAIT)
01310    {
01311 #ifndef NDEBUG
01312        fprintf(stderr,"kdeinit4: Debug wait activated.\n");
01313 #endif
01314        d.debug_wait = true;
01315    }
01316    if (request_data)
01317        free(request_data);
01318    return true;
01319 }
01320 
01321 static void handle_requests(pid_t waitForPid)
01322 {
01323    int max_sock = d.deadpipe[0];
01324    if (d.wrapper > max_sock)
01325       max_sock = d.wrapper;
01326    if (d.launcher[0] > max_sock)
01327       max_sock = d.launcher[0];
01328 #ifdef Q_WS_X11
01329    if (X11fd > max_sock)
01330       max_sock = X11fd;
01331 #endif
01332    max_sock++;
01333 
01334    while(1)
01335    {
01336       fd_set rd_set;
01337       fd_set wr_set;
01338       fd_set e_set;
01339       int result;
01340       pid_t exit_pid;
01341       int exit_status;
01342       char c;
01343 
01344       /* Flush the pipe of death */
01345       while( read(d.deadpipe[0], &c, 1) == 1)
01346         {}
01347 
01348       /* Handle dying children */
01349       do {
01350         exit_pid = waitpid(-1, &exit_status, WNOHANG);
01351         if (exit_pid > 0)
01352         {
01353 #ifndef NDEBUG
01354            fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid);
01355 #endif
01356            if (waitForPid && (exit_pid == waitForPid))
01357               return;
01358 
01359            if( WIFEXITED( exit_status )) // fix process return value
01360                exit_status = WEXITSTATUS(exit_status);
01361            else if( WIFSIGNALED( exit_status ))
01362                exit_status = 128 + WTERMSIG( exit_status );
01363            child_died(exit_pid, exit_status);
01364 
01365            if (d.wrapper < 0 && !children) {
01366 #ifndef NDEBUG
01367                fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n",
01368                                (long) getpid());
01369 #endif
01370                raise(SIGTERM);
01371            }
01372         }
01373       }
01374       while( exit_pid > 0);
01375 
01376       FD_ZERO(&rd_set);
01377       FD_ZERO(&wr_set);
01378       FD_ZERO(&e_set);
01379 
01380       if (d.launcher[0] >= 0)
01381          FD_SET(d.launcher[0], &rd_set);
01382       if (d.wrapper >= 0)
01383          FD_SET(d.wrapper, &rd_set);
01384       FD_SET(d.deadpipe[0], &rd_set);
01385 #ifdef Q_WS_X11
01386       if(X11fd >= 0) FD_SET(X11fd, &rd_set);
01387 #endif
01388 
01389       result = select(max_sock, &rd_set, &wr_set, &e_set, 0);
01390       if (result < 0) {
01391           if (errno == EINTR || errno == EAGAIN)
01392               continue;
01393           perror("kdeinit4: Aborting. select() failed");
01394           return;
01395       }
01396 
01397       /* Handle wrapper request */
01398       if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set))
01399       {
01400          struct sockaddr_un client;
01401          kde_socklen_t sClient = sizeof(client);
01402          int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient);
01403          if (sock >= 0)
01404          {
01405             d.accepted_fd = sock;
01406             handle_launcher_request(sock, "wrapper");
01407             close(sock);
01408             d.accepted_fd = -1;
01409          }
01410       }
01411 
01412       /* Handle launcher request */
01413       if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set))
01414       {
01415          if (!handle_launcher_request(d.launcher[0], "launcher"))
01416              launcher_died();
01417          if (waitForPid == d.launcher_pid)
01418             return;
01419       }
01420 
01421 #ifdef Q_WS_X11
01422       /* Look for incoming X11 events */
01423       if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) {
01424           if (X11display != 0) {
01425         XEvent event_return;
01426         while (XPending(X11display))
01427           XNextEvent(X11display, &event_return);
01428       }
01429       }
01430 #endif
01431    }
01432 }
01433 
01434 static void kdeinit_library_path()
01435 {
01436    const QStringList ltdl_library_path =
01437      QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(QLatin1Char(':'),QString::SkipEmptyParts);
01438 #ifdef Q_OS_DARWIN
01439    const QByteArray ldlibpath = qgetenv("DYLD_LIBRARY_PATH");
01440 #else
01441    const QByteArray ldlibpath = qgetenv("LD_LIBRARY_PATH");
01442 #endif
01443    const QStringList ld_library_path =
01444      QFile::decodeName(ldlibpath).split(QLatin1Char(':'),QString::SkipEmptyParts);
01445 
01446    QByteArray extra_path;
01447    const QStringList candidates = s_instance->dirs()->resourceDirs("lib");
01448    for (QStringList::ConstIterator it = candidates.begin();
01449         it != candidates.end();
01450         ++it)
01451    {
01452       QString d = *it;
01453       if (ltdl_library_path.contains(d))
01454           continue;
01455       if (ld_library_path.contains(d))
01456           continue;
01457       if (d[d.length()-1] == QLatin1Char('/'))
01458       {
01459          d.truncate(d.length()-1);
01460          if (ltdl_library_path.contains(d))
01461             continue;
01462          if (ld_library_path.contains(d))
01463             continue;
01464       }
01465       if ((d == QLatin1String("/lib")) || (d == QLatin1String("/usr/lib")))
01466          continue;
01467 
01468       QByteArray dir = QFile::encodeName(d);
01469 
01470       if (access(dir, R_OK))
01471           continue;
01472 
01473       if ( !extra_path.isEmpty())
01474          extra_path += ':';
01475       extra_path += dir;
01476    }
01477 
01478 //   if (!extra_path.isEmpty())
01479 //      lt_dlsetsearchpath(extra_path.data());
01480 
01481    QByteArray display = qgetenv(DISPLAY);
01482    if (display.isEmpty())
01483    {
01484 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
01485      fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n");
01486      exit(255);
01487 #endif
01488    }
01489    int i;
01490    if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
01491      display.truncate(i);
01492 
01493    display.replace(':','_');
01494 #ifdef __APPLE__
01495    display.replace('/','_');
01496 #endif
01497    // WARNING, if you change the socket name, adjust kwrapper too
01498    const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display));
01499    QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", socketFileName, *s_instance));
01500    if (socketName.length() >= MAX_SOCK_FILE)
01501    {
01502      fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
01503      fprintf(stderr, "         '%s'\n", socketName.data());
01504      exit(255);
01505    }
01506    strcpy(sock_file, socketName.data());
01507 }
01508 
01509 int kdeinit_xio_errhandler( Display *disp )
01510 {
01511     // disp is 0L when KDE shuts down. We don't want those warnings then.
01512 
01513     if ( disp )
01514     qWarning( "kdeinit4: Fatal IO error: client killed" );
01515 
01516     if (sock_file[0])
01517     {
01519       unlink(sock_file);
01520     }
01521 
01522     // Don't kill our children in suicide mode, they may still be in use
01523     if (d.suicide)
01524     {
01525        if (d.launcher_pid)
01526           kill(d.launcher_pid, SIGTERM);
01527        if (d.kded_pid)
01528           kill(d.kded_pid, SIGTERM);
01529        exit( 0 );
01530     }
01531 
01532     if ( disp )
01533     qWarning( "kdeinit4: sending SIGHUP to children." );
01534 
01535     /* this should remove all children we started */
01536     KDE_signal(SIGHUP, SIG_IGN);
01537     kill(0, SIGHUP);
01538 
01539     sleep(2);
01540 
01541     if ( disp )
01542     qWarning( "kdeinit4: sending SIGTERM to children." );
01543 
01544     /* and if they don't listen to us, this should work */
01545     KDE_signal(SIGTERM, SIG_IGN);
01546     kill(0, SIGTERM);
01547 
01548     if ( disp )
01549     qWarning( "kdeinit4: Exit." );
01550 
01551     exit( 0 );
01552     return 0;
01553 }
01554 
01555 #ifdef Q_WS_X11
01556 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err )
01557 {
01558 #ifndef NDEBUG
01559     char errstr[256];
01560     // kdeinit almost doesn't use X, and therefore there shouldn't be any X error
01561     XGetErrorText( dpy, err->error_code, errstr, 256 );
01562     fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n"
01563                     "         Major opcode: %d\n"
01564                     "         Minor opcode: %d\n"
01565                     "         Resource id:  0x%lx\n",
01566             getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid );
01567 
01568     //kDebug() << kBacktrace();
01569 
01570 #else
01571     Q_UNUSED(dpy);
01572     Q_UNUSED(err);
01573 #endif
01574     return 0;
01575 }
01576 #endif
01577 
01578 #ifdef Q_WS_X11
01579 // needs to be done sooner than initXconnection() because of also opening
01580 // another X connection for startup notification purposes
01581 static void setupX()
01582 {
01583     XSetIOErrorHandler(kdeinit_xio_errhandler);
01584     XSetErrorHandler(kdeinit_x_errhandler);
01585 /*
01586     Handle the tricky case of running via kdesu/su/sudo/etc. There the usual case
01587     is that kdesu (etc.) creates a file with xauth information, sets XAUTHORITY,
01588     runs the command and removes the xauth file after the command finishes. However,
01589     dbus and kdeinit daemon currently don't clean up properly and keeping running.
01590     Which means that running a KDE app via kdesu the second time talks to kdeinit
01591     with obsolete xauth information, which makes it unable to connect to X or launch
01592     any X11 applications.
01593     Even fixing the cleanup probably wouldn't be sufficient, since it'd be possible to
01594     launch one kdesu session, another one, exit the first one and the app from the second
01595     session would be using kdeinit from the first one.
01596     So the trick here is to duplicate the xauth file to another file in KDE's tmp
01597     location, make the file have a consistent name so that future sessions will use it
01598     as well, point XAUTHORITY there and never remove the file (except for possible
01599     tmp cleanup).
01600 */
01601     if( !qgetenv( "XAUTHORITY" ).isEmpty()) {
01602         QByteArray display = qgetenv( DISPLAY );
01603         int i;
01604         if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
01605             display.truncate(i);
01606         display.replace(':','_');
01607 #ifdef __APPLE__
01608         display.replace('/','_');
01609 #endif
01610         QString xauth = s_instance->dirs()->saveLocation( "tmp" ) + QLatin1String( "xauth-" )
01611             + QString::number( getuid()) + QLatin1String( "-" ) + QString::fromLocal8Bit( display );
01612         KSaveFile xauthfile( xauth );
01613         QFile xauthfrom( QFile::decodeName( qgetenv( "XAUTHORITY" )));
01614         if( !xauthfrom.open( QFile::ReadOnly ) || !xauthfile.open( QFile::WriteOnly )
01615             || xauthfile.write( xauthfrom.readAll()) != xauthfrom.size() || !xauthfile.finalize()) {
01616             xauthfile.abort();
01617         } else {
01618             setenv( "XAUTHORITY", QFile::encodeName( xauth ), true );
01619         }
01620     }
01621 }
01622 
01623 // Borrowed from kdebase/kaudio/kaudioserver.cpp
01624 static int initXconnection()
01625 {
01626   X11display = XOpenDisplay(NULL);
01627   if ( X11display != 0 ) {
01628     XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \
01629         0,
01630         BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)),
01631         BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) );
01632 #ifndef NDEBUG
01633     fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display));
01634 #endif
01635     int fd = XConnectionNumber( X11display );
01636     int on = 1;
01637     (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on));
01638     return fd;
01639   } else
01640     fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \
01641      "kdeinit4: Might not terminate at end of session.\n");
01642 
01643   return -1;
01644 }
01645 #endif
01646 
01647 extern "C" {
01648 
01649 static void secondary_child_handler(int)
01650 {
01651    waitpid(-1, 0, WNOHANG);
01652 }
01653 
01654 }
01655 
01656 int main(int argc, char **argv, char **envp)
01657 {
01658 #ifndef _WIN32_WCE
01659     setlocale (LC_ALL, "");
01660     setlocale (LC_NUMERIC, "C");
01661 #endif
01662 
01663    pid_t pid;
01664    bool do_fork = true;
01665    int launch_klauncher = 1;
01666    int launch_kded = 1;
01667    int keep_running = 1;
01668    d.suicide = false;
01669 
01671    char **safe_argv = (char **) malloc( sizeof(char *) * argc);
01672    for(int i = 0; i < argc; i++)
01673    {
01674       safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
01675       if (strcmp(safe_argv[i], "--no-klauncher") == 0)
01676          launch_klauncher = 0;
01677       if (strcmp(safe_argv[i], "--no-kded") == 0)
01678          launch_kded = 0;
01679 #ifdef Q_WS_MACX
01680       // make it nofork to match KUniqueApplication, technically command-line incompatible
01681       if (strcmp(safe_argv[i], "--nofork") == 0)
01682 #else
01683       if (strcmp(safe_argv[i], "--no-fork") == 0)
01684 #endif
01685          do_fork = false;
01686       if (strcmp(safe_argv[i], "--suicide") == 0)
01687          d.suicide = true;
01688       if (strcmp(safe_argv[i], "--exit") == 0)
01689          keep_running = 0;
01690       if (strcmp(safe_argv[i], "--version") == 0)
01691       {
01692      printf("Qt: %s\n", qVersion());
01693      printf("KDE: %s\n", KDE_VERSION_STRING);
01694      exit(0);
01695       }
01696 #ifdef KDEINIT_OOM_PROTECT
01697       if (strcmp(safe_argv[i], "--oom-pipe") == 0 && i+1<argc)
01698          oom_pipe = atol(argv[i+1]);
01699 #endif
01700       if (strcmp(safe_argv[i], "--help") == 0)
01701       {
01702         printf("Usage: kdeinit4 [options]\n");
01703      // printf("    --no-dcop         Do not start dcopserver\n");
01704 #ifdef Q_WS_MACX
01705         printf("    --nofork          Do not fork\n");
01706 #else
01707         printf("    --no-fork         Do not fork\n");
01708 #endif
01709      // printf("    --no-klauncher    Do not start klauncher\n");
01710         printf("    --no-kded         Do not start kded\n");
01711         printf("    --suicide         Terminate when no KDE applications are left running\n");
01712     printf("    --version         Show version information\n");
01713      // printf("    --exit            Terminate when kded has run\n");
01714         exit(0);
01715       }
01716    }
01717 
01718    cleanup_fds();
01719 
01720    // Redirect stdout to stderr. We have no reason to use stdout anyway.
01721    // This minimizes our impact on commands used in pipes.
01722    (void)dup2(2, 1);
01723 
01724    if (do_fork) {
01725 #ifdef Q_WS_MACX
01726       mac_fork_and_reexec_self();
01727 #else
01728       if (pipe(d.initpipe) != 0) {
01729           perror("kdeinit4: pipe failed");
01730           return 1;
01731       }
01732 
01733       // Fork here and let parent process exit.
01734       // Parent process may only exit after all required services have been
01735       // launched. (dcopserver/klauncher and services which start with '+')
01736       KDE_signal( SIGCHLD, secondary_child_handler);
01737       if (fork() > 0) // Go into background
01738       {
01739          close(d.initpipe[1]);
01740          d.initpipe[1] = -1;
01741          // wait till init is complete
01742          char c;
01743          while( read(d.initpipe[0], &c, 1) < 0)
01744             ;
01745          // then exit;
01746          close(d.initpipe[0]);
01747          d.initpipe[0] = -1;
01748          return 0;
01749       }
01750       close(d.initpipe[0]);
01751       d.initpipe[0] = -1;
01752 #endif
01753    }
01754 
01756    if(keep_running)
01757       setsid();
01758 
01760    s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
01761 
01763 #ifndef SKIP_PROCTITLE
01764    proctitle_init(argc, argv, envp);
01765 #endif
01766 
01767    kdeinit_library_path();
01768    // Don't make our instance the global instance
01769    // (do it only after kdeinit_library_path, that one indirectly uses KConfig,
01770    // which seems to be buggy and always use KGlobal instead of the matching KComponentData)
01771    Q_ASSERT(!KGlobal::hasMainComponent());
01772    // don't change envvars before proctitle_init()
01773    unsetenv("LD_BIND_NOW");
01774    unsetenv("DYLD_BIND_AT_LAUNCH");
01775    KApplication::loadedByKdeinit = true;
01776 
01777    d.maxname = strlen(argv[0]);
01778    d.launcher_pid = 0;
01779    d.kded_pid = 0;
01780    d.wrapper = -1;
01781    d.accepted_fd = -1;
01782    d.debug_wait = false;
01783    d.launcher_ok = false;
01784    children = NULL;
01785    init_signals();
01786 #ifdef Q_WS_X11
01787    setupX();
01788 #endif
01789 
01790    if (keep_running)
01791    {
01792       /*
01793        * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper
01794        * requests.
01795        */
01796       init_kdeinit_socket();
01797    }
01798 #ifdef Q_WS_X11
01799     if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty()) {
01800         const int extrasCount = sizeof(extra_libs)/sizeof(extra_libs[0]);
01801         for (int i=0; i<extrasCount; i++) {
01802             QString extra = KStandardDirs::locate("lib", QLatin1String(extra_libs[i]), *s_instance);
01803 
01804             // can't use KLibLoader here as it would unload the library
01805             // again
01806             if (!extra.isEmpty()) {
01807                 QLibrary l(extra);
01808                 l.setLoadHints(QLibrary::ExportExternalSymbolsHint);
01809                 l.load();
01810             }
01811 #ifndef NDEBUG
01812             else {
01813                 fprintf( stderr, "%s was not found.\n", extra_libs[i] );
01814             }
01815 #endif
01816 
01817         }
01818     }
01819 #endif
01820    if (launch_klauncher)
01821    {
01822       start_klauncher();
01823       handle_requests(d.launcher_pid); // Wait for klauncher to be ready
01824    }
01825 
01826 #ifdef Q_WS_X11
01827    X11fd = initXconnection();
01828 #endif
01829 
01830    {
01831       QFont::initialize();
01832 #ifdef Q_WS_X11
01833       if (XSupportsLocale ())
01834       {
01835          // Similar to QApplication::create_xim()
01836      // but we need to use our own display
01837      XOpenIM (X11display, 0, 0, 0);
01838       }
01839 #endif
01840    }
01841 
01842    if (launch_kded)
01843    {
01844       setenv("KDED_STARTED_BY_KDEINIT", "1", true);
01845       pid = launch( 1, KDED_EXENAME, 0 );
01846       unsetenv("KDED_STARTED_BY_KDEINIT");
01847 #ifndef NDEBUG
01848       fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result);
01849 #endif
01850       d.kded_pid = pid;
01851       handle_requests(pid);
01852    }
01853 
01854    for(int i = 1; i < argc; i++)
01855    {
01856       if (safe_argv[i][0] == '+')
01857       {
01858          pid = launch( 1, safe_argv[i]+1, 0);
01859 #ifndef NDEBUG
01860       fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result);
01861 #endif
01862          handle_requests(pid);
01863       }
01864       else if (safe_argv[i][0] == '-'
01865 #ifdef KDEINIT_OOM_PROTECT
01866           || isdigit(safe_argv[i][0])
01867 #endif
01868           )
01869       {
01870          // Ignore
01871       }
01872       else
01873       {
01874          pid = launch( 1, safe_argv[i], 0 );
01875 #ifndef NDEBUG
01876       fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result);
01877 #endif
01878       }
01879    }
01880 
01882    for(int i = 0; i < argc; i++)
01883    {
01884       free(safe_argv[i]);
01885    }
01886    free (safe_argv);
01887 
01888 #ifndef SKIP_PROCTITLE
01889    proctitle_set("kdeinit4 Running...");
01890 #endif
01891 
01892    if (!keep_running)
01893       return 0;
01894 
01895    if (d.initpipe[1] != -1)
01896    {
01897       char c = 0;
01898       write(d.initpipe[1], &c, 1); // Kdeinit is started.
01899       close(d.initpipe[1]);
01900       d.initpipe[1] = -1;
01901    }
01902 
01903    handle_requests(0);
01904 
01905    return 0;
01906 }
01907 
01908 

KInit

Skip menu "KInit"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • 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