• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KInit

kinit.cpp

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

KInit

Skip menu "KInit"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal