kinit.cpp
00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (c) 1999-2000 Waldo Bastian <bastian@kde.org> 00004 * (c) 1999 Mario Weilguni <mweilguni@sime.com> 00005 * (c) 2001 Lubos Lunak <l.lunak@kde.org> 00006 * 00007 * $Id: kinit.cpp 698691 2007-08-10 18:22:59Z mueller $ 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 <qstring.h> 00049 #include <qfile.h> 00050 #include <qdatetime.h> 00051 #include <qfileinfo.h> 00052 #include <qtextstream.h> 00053 #include <qregexp.h> 00054 #include <qfont.h> 00055 #include <kinstance.h> 00056 #include <kstandarddirs.h> 00057 #include <kglobal.h> 00058 #include <kconfig.h> 00059 #include <klibloader.h> 00060 #include <kapplication.h> 00061 #include <klocale.h> 00062 00063 #ifdef Q_OS_LINUX 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 <kstartupinfo.h> // schroder 00072 #endif 00073 00074 #include <kdeversion.h> 00075 00076 #include "ltdl.h" 00077 #include "klauncher_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(KDEINIT_USE_XFT) && defined(KDEINIT_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 KInstance *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 QCString 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 kdeinit_xio_errhandler( Display * ); 00165 int kdeinit_x_errhandler( Display *, XErrorEvent *err ); 00166 } 00167 #endif 00168 00169 /* These are to link libkparts even if 'smart' linker is used */ 00170 #include <kparts/plugin.h> 00171 extern "C" KParts::Plugin* _kinit_init_kparts() { return new KParts::Plugin(); } 00172 /* These are to link libkio even if 'smart' linker is used */ 00173 #include <kio/authinfo.h> 00174 extern "C" KIO::AuthInfo* _kioslave_init_kio() { return new KIO::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 QString &errorMsg) 00240 { 00241 fprintf( stderr, "%s\n", errorMsg.local8Bit().data() ); 00242 QCString 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 perror( "kdeinit: couldn't open() tty" ); 00260 return; 00261 } 00262 if( dup2( fd, STDOUT_FILENO ) < 0 ) 00263 { 00264 perror( "kdeinit: couldn't dup2() tty" ); 00265 close( fd ); 00266 return; 00267 } 00268 if( dup2( fd, STDERR_FILENO ) < 0 ) 00269 { 00270 perror( "kdeinit: couldn't dup2() tty" ); 00271 close( fd ); 00272 return; 00273 } 00274 close( fd ); 00275 } 00276 00277 // from kdecore/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( KStartupInfoId& 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 KStartupInfoData data; 00332 int desktop = get_current_desktop( X11_startup_notify_display ); 00333 data.setDesktop( desktop ); 00334 data.setBin( bin ); 00335 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data ); 00336 XFlush( X11_startup_notify_display ); 00337 } 00338 00339 static void complete_startup_info( KStartupInfoId& id, pid_t pid ) 00340 { 00341 if( X11_startup_notify_display == NULL ) 00342 return; 00343 if( pid == 0 ) // failure 00344 KStartupInfo::sendFinishX( X11_startup_notify_display, id ); 00345 else 00346 { 00347 KStartupInfoData data; 00348 data.addPid( pid ); 00349 data.setHostname(); 00350 KStartupInfo::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 QCString execpath_avoid_loops( const QCString& exec, int envc, const char* envs, bool avoid_loops ) 00359 { 00360 QStringList 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 = QStringList::split( QRegExp( "[:\b]" ), path, true ); 00366 } 00367 else 00368 paths = QStringList::split( QRegExp( "[:\b]" ), getenv( "PATH" ), true ); 00369 QCString execpath = QFile::encodeName( 00370 s_instance->dirs()->findExe( exec, paths.join( QString( ":" )))); 00371 if( avoid_loops && !execpath.isEmpty()) 00372 { 00373 int pos = execpath.findRev( '/' ); 00374 QString bin_path = execpath.left( pos ); 00375 for( QStringList::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 = QFile::encodeName( 00384 s_instance->dirs()->findExe( exec, paths.join( QString( ":" )))); 00385 } 00386 return execpath; 00387 } 00388 00389 #ifdef KDEINIT_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 QCString lib; 00429 QCString name; 00430 QCString exec; 00431 00432 if (strcmp(_name, "klauncher") == 0) { 00433 /* klauncher 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("kdeinit: socketpair() failed!\n"); 00439 exit(255); 00440 } 00441 launcher = 1; 00442 } 00443 00444 QCString libpath; 00445 QCString execpath; 00446 if (_name[0] != '/') 00447 { 00448 /* Relative name without '.la' */ 00449 name = _name; 00450 lib = name + ".la"; 00451 exec = name; 00452 libpath = QFile::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("kdeinit: 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 KStartupInfoId 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("kdeinit: 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 QStrList 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( QStrListIterator it( unset_envs ); 00534 it.current() != NULL ; 00535 ++it ) 00536 { 00537 QCString 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 KStartupInfo::resetStartupEnv(); 00555 else 00556 startup_id.setupStartupEnv(); 00557 #endif 00558 { 00559 int r; 00560 QCString 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 Q_OS_LINUX 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 kdeinit_setproctitle( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00579 else 00580 kdeinit_setproctitle( "kdeinit: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00581 #else 00582 kdeinit_setproctitle( "kdeinit: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00583 #endif 00584 } 00585 00586 d.handle = 0; 00587 if (libpath.isEmpty() && execpath.isEmpty()) 00588 { 00589 QString errorMsg = i18n("Could not find '%1' executable.").arg(QFile::decodeName(_name)); 00590 exitWithErrorMsg(errorMsg); 00591 } 00592 00593 if ( getenv("KDE_IS_PRELINKED") && !execpath.isEmpty() && !launcher) 00594 libpath.truncate(0); 00595 00596 if ( !libpath.isEmpty() ) 00597 { 00598 d.handle = lt_dlopen( QFile::encodeName(libpath) ); 00599 if (!d.handle ) 00600 { 00601 const char * ltdlError = lt_dlerror(); 00602 if (execpath.isEmpty()) 00603 { 00604 // Error 00605 QString errorMsg = i18n("Could not open library '%1'.\n%2").arg(QFile::decodeName(libpath)) 00606 .arg(ltdlError ? QFile::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, "kdeinitmain"); 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 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2").arg(libpath) 00649 .arg(ltdlError ? QFile::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, "kdeinit: Suspending process\n" 00663 "kdeinit: 'gdb kdeinit %d' to debug\n" 00664 "kdeinit: '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, "Could not load library! Trying exec....\n"); 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 QCString 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("kdeinit: Pipe closed unexpectedly"); 00732 d.result = 1; // Error 00733 break; 00734 } 00735 perror("kdeinit: 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("kdeinit: 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("kdeinit: 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("kdeinit: 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_kdeinit_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, "kdeinit: Aborting. $HOME not set!"); 00835 exit(255); 00836 } 00837 chdir(home_dir); 00838 00839 { 00840 QCString path = home_dir; 00841 QCString readOnly = getenv("KDE_HOME_READONLY"); 00842 if (access(path.data(), R_OK|W_OK)) 00843 { 00844 if (errno == ENOENT) 00845 { 00846 fprintf(stderr, "kdeinit: Aborting. $HOME directory (%s) does not exist.\n", path.data()); 00847 exit(255); 00848 } 00849 else if (readOnly.isEmpty()) 00850 { 00851 fprintf(stderr, "kdeinit: 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, "kdeinit: 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, "kdeinit: 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, "kdeinit: Shutting down running client.\n"); 00894 klauncher_header request_header; 00895 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT; 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("kdeinit: Aborting. socket() failed: "); 00912 exit(255); 00913 } 00914 00915 options = fcntl(d.wrapper, F_GETFL); 00916 if (options == -1) 00917 { 00918 perror("kdeinit: 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("kdeinit: 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("kdeinit: 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("kdeinit: 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("kdeinit: 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("kdeinit: Aborting. socket() failed: "); 00972 return; 00973 } 00974 00975 options = fcntl(d.wrapper_old, F_GETFL); 00976 if (options == -1) 00977 { 00978 // perror("kdeinit: 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("kdeinit: 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("kdeinit: 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("kdeinit: 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, "kdeinit: Communication error with launcher. Exiting!\n"); 01073 ::exit(255); 01074 return; 01075 } 01076 01077 // KLauncher died... restart 01078 #ifndef NDEBUG 01079 fprintf(stderr, "kdeinit: KLauncher 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, "klauncher", 0 ); 01094 #ifndef NDEBUG 01095 fprintf(stderr, "kdeinit: Relaunching KLauncher, 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 klauncher_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 klauncher_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, "kdeinit: 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, "kdeinit: 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 QCString olddisplay = getenv(DISPLAY); 01230 QCString kdedisplay = getenv("KDE_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("KDE_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, "kdeinit: Got SETENV '%s=%s' from klauncher.\n", env_name, env_value); 01277 else 01278 fprintf(stderr, "kdeinit: 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, "kdeinit: 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,"kdeinit: terminate KDE.\n"); 01296 #endif 01297 #ifdef Q_WS_X11 01298 kdeinit_xio_errhandler( 0L ); 01299 #endif 01300 } 01301 else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT) 01302 { 01303 #ifndef NDEBUG 01304 fprintf(stderr,"kdeinit: Killing kdeinit/klauncher.\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,"kdeinit: 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 #ifndef NDEBUG 01354 fprintf(stderr, "kdeinit: PID %ld terminated.\n", (long) exit_pid); 01355 #endif 01356 if (waitForPid && (exit_pid == waitForPid)) 01357 return; 01358 01359 if (d.launcher_pid) 01360 { 01361 // TODO send process died message 01362 klauncher_header request_header; 01363 long request_data[2]; 01364 request_header.cmd = LAUNCHER_DIED; 01365 request_header.arg_length = sizeof(long) * 2; 01366 request_data[0] = exit_pid; 01367 request_data[1] = 0; /* not implemented yet */ 01368 write(d.launcher[0], &request_header, sizeof(request_header)); 01369 write(d.launcher[0], request_data, request_header.arg_length); 01370 } 01371 } 01372 } 01373 while( exit_pid > 0); 01374 01375 FD_ZERO(&rd_set); 01376 FD_ZERO(&wr_set); 01377 FD_ZERO(&e_set); 01378 01379 if (d.launcher_pid) 01380 { 01381 FD_SET(d.launcher[0], &rd_set); 01382 } 01383 FD_SET(d.wrapper, &rd_set); 01384 if (d.wrapper_old) 01385 { 01386 FD_SET(d.wrapper_old, &rd_set); 01387 } 01388 FD_SET(d.deadpipe[0], &rd_set); 01389 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 01390 //#ifdef Q_WS_X11 01391 if(X11fd >= 0) FD_SET(X11fd, &rd_set); 01392 #endif 01393 01394 result = select(max_sock, &rd_set, &wr_set, &e_set, 0); 01395 01396 /* Handle wrapper request */ 01397 if ((result > 0) && (FD_ISSET(d.wrapper, &rd_set))) 01398 { 01399 struct sockaddr_un client; 01400 kde_socklen_t sClient = sizeof(client); 01401 int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient); 01402 if (sock >= 0) 01403 { 01404 #if defined(KDEINIT_USE_XFT) && defined(KDEINIT_USE_FONTCONFIG) 01405 if( FcGetVersion() < 20390 && !FcConfigUptoDate(NULL)) 01406 FcInitReinitialize(); 01407 #endif 01408 if (fork() == 0) 01409 { 01410 close_fds(); 01411 reset_oom_protect(); 01412 handle_launcher_request(sock); 01413 exit(255); /* Terminate process. */ 01414 } 01415 close(sock); 01416 } 01417 } 01418 if ((result > 0) && (FD_ISSET(d.wrapper_old, &rd_set))) 01419 { 01420 struct sockaddr_un client; 01421 kde_socklen_t sClient = sizeof(client); 01422 int sock = accept(d.wrapper_old, (struct sockaddr *)&client, &sClient); 01423 if (sock >= 0) 01424 { 01425 #if defined(KDEINIT_USE_XFT) && defined(KDEINIT_USE_FONTCONFIG) 01426 if( FcGetVersion() < 20390 && !FcConfigUptoDate(NULL)) 01427 FcInitReinitialize(); 01428 #endif 01429 if (fork() == 0) 01430 { 01431 close_fds(); 01432 reset_oom_protect(); 01433 handle_launcher_request(sock); 01434 exit(255); /* Terminate process. */ 01435 } 01436 close(sock); 01437 } 01438 } 01439 01440 /* Handle launcher request */ 01441 if ((result > 0) && (d.launcher_pid) && (FD_ISSET(d.launcher[0], &rd_set))) 01442 { 01443 handle_launcher_request(); 01444 if (waitForPid == d.launcher_pid) 01445 return; 01446 } 01447 01448 //#if defined Q_WS_X11 && ! defined K_WS_QTONLY 01449 #ifdef Q_WS_X11 01450 /* Look for incoming X11 events */ 01451 if((result > 0) && (X11fd >= 0)) 01452 { 01453 if(FD_ISSET(X11fd,&rd_set)) 01454 { 01455 if (X11display != 0) { 01456 XEvent event_return; 01457 while (XPending(X11display)) 01458 XNextEvent(X11display, &event_return); 01459 } 01460 } 01461 } 01462 #endif 01463 } 01464 } 01465 01466 static void kdeinit_library_path() 01467 { 01468 QStringList ltdl_library_path = 01469 QStringList::split(':', QFile::decodeName(getenv("LTDL_LIBRARY_PATH"))); 01470 QStringList ld_library_path = 01471 QStringList::split(':', QFile::decodeName(getenv("LD_LIBRARY_PATH"))); 01472 01473 QCString extra_path; 01474 QStringList candidates = s_instance->dirs()->resourceDirs("lib"); 01475 for (QStringList::ConstIterator it = candidates.begin(); 01476 it != candidates.end(); 01477 it++) 01478 { 01479 QString d = *it; 01480 if (ltdl_library_path.contains(d)) 01481 continue; 01482 if (ld_library_path.contains(d)) 01483 continue; 01484 if (d[d.length()-1] == '/') 01485 { 01486 d.truncate(d.length()-1); 01487 if (ltdl_library_path.contains(d)) 01488 continue; 01489 if (ld_library_path.contains(d)) 01490 continue; 01491 } 01492 if ((d == "/lib") || (d == "/usr/lib")) 01493 continue; 01494 01495 QCString dir = QFile::encodeName(d); 01496 01497 if (access(dir, R_OK)) 01498 continue; 01499 01500 if ( !extra_path.isEmpty()) 01501 extra_path += ":"; 01502 extra_path += dir; 01503 } 01504 01505 if (lt_dlinit()) 01506 { 01507 const char * ltdlError = lt_dlerror(); 01508 fprintf(stderr, "can't initialize dynamic loading: %s\n", ltdlError != 0 ? ltdlError : "(null)" ); 01509 } 01510 if (!extra_path.isEmpty()) 01511 lt_dlsetsearchpath(extra_path.data()); 01512 01513 QCString display = getenv(DISPLAY); 01514 if (display.isEmpty()) 01515 { 01516 fprintf(stderr, "kdeinit: Aborting. $"DISPLAY" is not set.\n"); 01517 exit(255); 01518 } 01519 int i; 01520 if((i = display.findRev('.')) > display.findRev(':') && i >= 0) 01521 display.truncate(i); 01522 01523 QCString socketName = QFile::encodeName(locateLocal("socket", QString("kdeinit-%1").arg(display), s_instance)); 01524 if (socketName.length() >= MAX_SOCK_FILE) 01525 { 01526 fprintf(stderr, "kdeinit: Aborting. Socket name will be too long:\n"); 01527 fprintf(stderr, " '%s'\n", socketName.data()); 01528 exit(255); 01529 } 01530 strcpy(sock_file_old, socketName.data()); 01531 01532 display.replace(":","_"); 01533 socketName = QFile::encodeName(locateLocal("socket", QString("kdeinit_%1").arg(display), s_instance)); 01534 if (socketName.length() >= MAX_SOCK_FILE) 01535 { 01536 fprintf(stderr, "kdeinit: Aborting. Socket name will be too long:\n"); 01537 fprintf(stderr, " '%s'\n", socketName.data()); 01538 exit(255); 01539 } 01540 strcpy(sock_file, socketName.data()); 01541 } 01542 01543 int kdeinit_xio_errhandler( Display *disp ) 01544 { 01545 // disp is 0L when KDE shuts down. We don't want those warnings then. 01546 01547 if ( disp ) 01548 qWarning( "kdeinit: Fatal IO error: client killed" ); 01549 01550 if (sock_file[0]) 01551 { 01553 unlink(sock_file); 01554 } 01555 if (sock_file_old[0]) 01556 { 01558 unlink(sock_file_old); 01559 } 01560 01561 // Don't kill our children in suicide mode, they may still be in use 01562 if (d.suicide) 01563 { 01564 if (d.launcher_pid) 01565 kill(d.launcher_pid, SIGTERM); 01566 exit( 0 ); 01567 } 01568 01569 if ( disp ) 01570 qWarning( "kdeinit: sending SIGHUP to children." ); 01571 01572 /* this should remove all children we started */ 01573 signal(SIGHUP, SIG_IGN); 01574 kill(0, SIGHUP); 01575 01576 sleep(2); 01577 01578 if ( disp ) 01579 qWarning( "kdeinit: sending SIGTERM to children." ); 01580 01581 /* and if they don't listen to us, this should work */ 01582 signal(SIGTERM, SIG_IGN); 01583 kill(0, SIGTERM); 01584 01585 if ( disp ) 01586 qWarning( "kdeinit: Exit." ); 01587 01588 exit( 0 ); 01589 return 0; 01590 } 01591 01592 #ifdef Q_WS_X11 01593 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err ) 01594 { 01595 #ifndef NDEBUG 01596 char errstr[256]; 01597 // kdeinit almost doesn't use X, and therefore there shouldn't be any X error 01598 XGetErrorText( dpy, err->error_code, errstr, 256 ); 01599 fprintf(stderr, "kdeinit: KDE detected X Error: %s %d\n" 01600 " Major opcode: %d\n" 01601 " Minor opcode: %d\n" 01602 " Resource id: 0x%lx\n", 01603 errstr, err->error_code, err->request_code, err->minor_code, err->resourceid ); 01604 #else 01605 Q_UNUSED(dpy); 01606 Q_UNUSED(err); 01607 #endif 01608 return 0; 01609 } 01610 #endif 01611 01612 //#if defined Q_WS_X11 && ! defined K_WS_QTONLY 01613 #ifdef Q_WS_X11 01614 // needs to be done sooner than initXconnection() because of also opening 01615 // another X connection for startup notification purposes 01616 static void setupX() 01617 { 01618 XSetIOErrorHandler(kdeinit_xio_errhandler); 01619 XSetErrorHandler(kdeinit_x_errhandler); 01620 } 01621 01622 // Borrowed from kdebase/kaudio/kaudioserver.cpp 01623 static int initXconnection() 01624 { 01625 X11display = XOpenDisplay(NULL); 01626 if ( X11display != 0 ) { 01627 XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \ 01628 0, 01629 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)), 01630 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) ); 01631 #ifndef NDEBUG 01632 fprintf(stderr, "kdeinit: opened connection to %s\n", DisplayString(X11display)); 01633 #endif 01634 int fd = XConnectionNumber( X11display ); 01635 int on = 1; 01636 (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on)); 01637 return fd; 01638 } else 01639 fprintf(stderr, "kdeinit: Can't connect to the X Server.\n" \ 01640 "kdeinit: Might not terminate at end of session.\n"); 01641 01642 return -1; 01643 } 01644 #endif 01645 01646 #ifdef __KCC 01647 /* One of my horrible hacks. KCC includes in each "main" function a call 01648 to _main(), which is provided by the C++ runtime system. It is 01649 responsible for calling constructors for some static objects. That must 01650 be done only once, so _main() is guarded against multiple calls. 01651 For unknown reasons the designers of KAI's libKCC decided it would be 01652 a good idea to actually abort() when it's called multiple times, instead 01653 of ignoring further calls. This breaks our mechanism of KLM's, because 01654 most KLM's have a main() function which is called from us. 01655 The "solution" is to simply define our own _main(), which ignores multiple 01656 calls, which is easy, and which does the same work as KAI'c _main(), 01657 which is difficult. Currently (KAI 4.0f) it only calls __call_ctors(void) 01658 (a C++ function), but if that changes we need to change our's too. 01659 (matz) */ 01660 /* 01661 Those 'unknown reasons' are C++ standard forbidding recursive calls to main() 01662 or any means that would possibly allow that (e.g. taking address of main()). 01663 The correct solution is not using main() as entry point for kdeinit modules, 01664 but only kdemain(). 01665 */ 01666 extern "C" void _main(void); 01667 extern "C" void __call_ctors__Fv(void); 01668 static int main_called = 0; 01669 void _main(void) 01670 { 01671 if (main_called) 01672 return; 01673 main_called = 1; 01674 __call_ctors__Fv (); 01675 } 01676 #endif 01677 01678 static void secondary_child_handler(int) 01679 { 01680 waitpid(-1, 0, WNOHANG); 01681 } 01682 01683 int main(int argc, char **argv, char **envp) 01684 { 01685 int i; 01686 pid_t pid; 01687 int launch_dcop = 1; 01688 int launch_klauncher = 1; 01689 int launch_kded = 1; 01690 int keep_running = 1; 01691 int new_startup = 0; 01692 d.suicide = false; 01693 01695 char **safe_argv = (char **) malloc( sizeof(char *) * argc); 01696 for(i = 0; i < argc; i++) 01697 { 01698 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]); 01699 if (strcmp(safe_argv[i], "--no-dcop") == 0) 01700 launch_dcop = 0; 01701 if (strcmp(safe_argv[i], "--no-klauncher") == 0) 01702 launch_klauncher = 0; 01703 if (strcmp(safe_argv[i], "--no-kded") == 0) 01704 launch_kded = 0; 01705 if (strcmp(safe_argv[i], "--suicide") == 0) 01706 d.suicide = true; 01707 if (strcmp(safe_argv[i], "--exit") == 0) 01708 keep_running = 0; 01709 if (strcmp(safe_argv[i], "--new-startup") == 0) 01710 new_startup = 1; 01711 #ifdef KDEINIT_OOM_PROTECT 01712 if (strcmp(safe_argv[i], "--oom-pipe") == 0 && i+1<argc) 01713 oom_pipe = atol(argv[i+1]); 01714 #endif 01715 if (strcmp(safe_argv[i], "--help") == 0) 01716 { 01717 printf("Usage: kdeinit [options]\n"); 01718 // printf(" --no-dcop Do not start dcopserver\n"); 01719 // printf(" --no-klauncher Do not start klauncher\n"); 01720 printf(" --no-kded Do not start kded\n"); 01721 printf(" --suicide Terminate when no KDE applications are left running\n"); 01722 // printf(" --exit Terminate when kded has run\n"); 01723 exit(0); 01724 } 01725 } 01726 01727 pipe(d.initpipe); 01728 01729 // Fork here and let parent process exit. 01730 // Parent process may only exit after all required services have been 01731 // launched. (dcopserver/klauncher and services which start with '+') 01732 signal( SIGCHLD, secondary_child_handler); 01733 if (fork() > 0) // Go into background 01734 { 01735 close(d.initpipe[1]); 01736 d.initpipe[1] = -1; 01737 // wait till init is complete 01738 char c; 01739 while( read(d.initpipe[0], &c, 1) < 0); 01740 // then exit; 01741 close(d.initpipe[0]); 01742 d.initpipe[0] = -1; 01743 return 0; 01744 } 01745 close(d.initpipe[0]); 01746 d.initpipe[0] = -1; 01747 d.my_pid = getpid(); 01748 01750 if(keep_running) 01751 setsid(); 01752 01754 s_instance = new KInstance("kdeinit"); 01755 01757 kdeinit_initsetproctitle(argc, argv, envp); 01758 kdeinit_library_path(); 01759 // Don't make our instance the global instance 01760 // (do it only after kdeinit_library_path, that one indirectly uses KConfig, 01761 // which seems to be buggy and always use KGlobal instead of the maching KInstance) 01762 KGlobal::_instance = 0L; 01763 // don't change envvars before kdeinit_initsetproctitle() 01764 unsetenv("LD_BIND_NOW"); 01765 unsetenv("DYLD_BIND_AT_LAUNCH"); 01766 KApplication::loadedByKdeinit = true; 01767 01768 d.maxname = strlen(argv[0]); 01769 d.launcher_pid = 0; 01770 d.wrapper = 0; 01771 d.wrapper_old = 0; 01772 d.debug_wait = false; 01773 d.launcher_ok = false; 01774 d.lt_dlopen_flag = lt_dlopen_flag; 01775 lt_dlopen_flag |= LTDL_GLOBAL; 01776 init_signals(); 01777 #ifdef Q_WS_X11 01778 setupX(); 01779 #endif 01780 01781 if (keep_running) 01782 { 01783 /* 01784 * Create ~/.kde/tmp-<hostname>/kdeinit-<display> socket for incoming wrapper 01785 * requests. 01786 */ 01787 init_kdeinit_socket(); 01788 } 01789 01790 if (launch_dcop) 01791 { 01792 if (d.suicide) 01793 pid = launch( 3, "dcopserver", "--nosid\0--suicide" ); 01794 else 01795 pid = launch( 2, "dcopserver", "--nosid" ); 01796 #ifndef NDEBUG 01797 fprintf(stderr, "kdeinit: Launched DCOPServer, pid = %ld result = %d\n", (long) pid, d.result); 01798 #endif 01799 WaitPid(pid); 01800 if (!WIFEXITED(d.exit_status) || (WEXITSTATUS(d.exit_status) != 0)) 01801 { 01802 fprintf(stderr, "kdeinit: DCOPServer could not be started, aborting.\n"); 01803 exit(1); 01804 } 01805 } 01806 #ifndef __CYGWIN__ 01807 if (!d.suicide && !getenv("KDE_IS_PRELINKED")) 01808 { 01809 QString konq = locate("lib", "libkonq.la", s_instance); 01810 if (!konq.isEmpty()) 01811 (void) lt_dlopen(QFile::encodeName(konq).data()); 01812 } 01813 #endif 01814 if (launch_klauncher) 01815 { 01816 if( new_startup ) 01817 pid = launch( 2, "klauncher", "--new-startup" ); 01818 else 01819 pid = launch( 1, "klauncher", 0 ); 01820 #ifndef NDEBUG 01821 fprintf(stderr, "kdeinit: Launched KLauncher, pid = %ld result = %d\n", (long) pid, d.result); 01822 #endif 01823 handle_requests(pid); // Wait for klauncher to be ready 01824 } 01825 01826 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 01827 //#ifdef Q_WS_X11 01828 X11fd = initXconnection(); 01829 #endif 01830 01831 { 01832 #if defined(KDEINIT_USE_XFT) && defined(KDEINIT_USE_FONTCONFIG) 01833 if( FcGetVersion() < 20390 ) 01834 { 01835 XftInit(0); 01836 XftInitFtLibrary(); 01837 } 01838 #endif 01839 QFont::initialize(); 01840 setlocale (LC_ALL, ""); 01841 setlocale (LC_NUMERIC, "C"); 01842 #ifdef Q_WS_X11 01843 if (XSupportsLocale ()) 01844 { 01845 // Similar to QApplication::create_xim() 01846 // but we need to use our own display 01847 XOpenIM (X11display, 0, 0, 0); 01848 } 01849 #endif 01850 } 01851 01852 if (launch_kded) 01853 { 01854 if( new_startup ) 01855 pid = launch( 2, "kded", "--new-startup" ); 01856 else 01857 pid = launch( 1, "kded", 0 ); 01858 #ifndef NDEBUG 01859 fprintf(stderr, "kdeinit: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result); 01860 #endif 01861 handle_requests(pid); 01862 } 01863 01864 for(i = 1; i < argc; i++) 01865 { 01866 if (safe_argv[i][0] == '+') 01867 { 01868 pid = launch( 1, safe_argv[i]+1, 0); 01869 #ifndef NDEBUG 01870 fprintf(stderr, "kdeinit: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result); 01871 #endif 01872 handle_requests(pid); 01873 } 01874 else if (safe_argv[i][0] == '-' 01875 #ifdef KDEINIT_OOM_PROTECT 01876 || isdigit(safe_argv[i][0]) 01877 #endif 01878 ) 01879 { 01880 // Ignore 01881 } 01882 else 01883 { 01884 pid = launch( 1, safe_argv[i], 0 ); 01885 #ifndef NDEBUG 01886 fprintf(stderr, "kdeinit: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result); 01887 #endif 01888 } 01889 } 01890 01892 for(i = 0; i < argc; i++) 01893 { 01894 free(safe_argv[i]); 01895 } 01896 free (safe_argv); 01897 01898 kdeinit_setproctitle("kdeinit Running..."); 01899 01900 if (!keep_running) 01901 return 0; 01902 01903 char c = 0; 01904 write(d.initpipe[1], &c, 1); // Kdeinit is started. 01905 close(d.initpipe[1]); 01906 d.initpipe[1] = -1; 01907 01908 handle_requests(0); 01909 01910 return 0; 01911 } 01912