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

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.6.3
This website is maintained by Timothy Pearson.