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