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
Trinity API Reference