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