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