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

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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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