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

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
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.6
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