• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeinit
 

tdeinit

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

tdeinit

Skip menu "tdeinit"
  • Main Page
  • File List
  • Related Pages

tdeinit

Skip menu "tdeinit"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeinit by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.