kinit.cpp

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