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