KInit
kinit.cpp
Go to the documentation of this file.
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 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License version 2 as published by the Free Software Foundation. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Library General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Library General Public License 00017 * along with this library; see the file COPYING.LIB. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #define QT_NO_CAST_FROM_ASCII 00023 00024 #include <config.h> 00025 #include <config-kdeinit.h> 00026 00027 #include <sys/types.h> 00028 #include <sys/time.h> 00029 #include <sys/resource.h> 00030 #include <sys/stat.h> 00031 #include <sys/socket.h> 00032 #include <sys/un.h> 00033 #include <sys/wait.h> 00034 #ifdef HAVE_SYS_SELECT_H 00035 #include <sys/select.h> // Needed on some systems. 00036 #endif 00037 00038 #include <ctype.h> 00039 #include <errno.h> 00040 #include <fcntl.h> 00041 #include "proctitle.h" 00042 #include <signal.h> 00043 #include <stdio.h> 00044 #include <stdlib.h> 00045 #include <string.h> 00046 #include <unistd.h> 00047 #include <locale.h> 00048 00049 #include <QtCore/QLibrary> 00050 #include <QtCore/QString> 00051 #include <QtCore/QFile> 00052 #include <QtCore/QDate> 00053 #include <QtCore/QFileInfo> 00054 #include <QtCore/QRegExp> 00055 #include <QtGui/QFont> 00056 #include <kcomponentdata.h> 00057 #include <klibrary.h> 00058 #include <kdemacros.h> 00059 #include <kstandarddirs.h> 00060 #include <kglobal.h> 00061 #include <kconfig.h> 00062 #include <kapplication.h> 00063 #include <klocale.h> 00064 #include <kdebug.h> 00065 #include <kde_file.h> 00066 #include <ksavefile.h> 00067 00068 #ifdef Q_OS_LINUX 00069 #include <sys/prctl.h> 00070 #ifndef PR_SET_NAME 00071 #define PR_SET_NAME 15 00072 #endif 00073 #endif 00074 00075 #ifdef Q_WS_MACX 00076 #include <kkernel_mac.h> 00077 #endif 00078 00079 #include <kdeversion.h> 00080 00081 #include "klauncher_cmds.h" 00082 00083 #ifdef Q_WS_X11 00084 #include <X11/Xlib.h> 00085 #include <X11/Xatom.h> 00086 #include <fixx11h.h> 00087 #include <kstartupinfo.h> 00088 #endif 00089 00090 #ifdef Q_WS_X11 00091 static const char *extra_libs[] = { 00092 "libkio.so.5", 00093 "libkparts.so.4", 00094 #ifdef __KDE_HAVE_GCC_VISIBILITY 00095 "libplasma.so.3" 00096 #endif 00097 }; 00098 #endif 00099 00100 // #define SKIP_PROCTITLE 1 00101 00102 extern char **environ; 00103 00104 #ifdef Q_WS_X11 00105 static int X11fd = -1; 00106 static Display *X11display = 0; 00107 static int X11_startup_notify_fd = -1; 00108 static Display *X11_startup_notify_display = 0; 00109 #endif 00110 static KComponentData *s_instance = 0; 00111 #define MAX_SOCK_FILE 255 00112 static char sock_file[MAX_SOCK_FILE]; 00113 00114 #ifdef Q_WS_X11 00115 #define DISPLAY "DISPLAY" 00116 #elif defined(Q_WS_QWS) 00117 #define DISPLAY "QWS_DISPLAY" 00118 #elif defined(Q_WS_MACX) 00119 #define DISPLAY "MAC_DISPLAY" 00120 #elif defined(Q_WS_WIN) 00121 #define DISPLAY "WIN_DISPLAY" 00122 #else 00123 #error Use QT/X11 or QT/Embedded 00124 #endif 00125 00126 /* Group data */ 00127 static struct { 00128 int maxname; 00129 int fd[2]; 00130 int launcher[2]; /* socket pair for launcher communication */ 00131 int deadpipe[2]; /* pipe used to detect dead children */ 00132 int initpipe[2]; 00133 int wrapper; /* socket for wrapper communication */ 00134 int accepted_fd; /* socket accepted and that must be closed in the child process */ 00135 char result; 00136 int exit_status; 00137 pid_t fork; 00138 pid_t launcher_pid; 00139 pid_t kded_pid; 00140 int n; 00141 char **argv; 00142 int (*func)(int, char *[]); 00143 int (*launcher_func)(int); 00144 bool debug_wait; 00145 QByteArray errorMsg; 00146 bool launcher_ok; 00147 bool suicide; 00148 } d; 00149 00150 struct child 00151 { 00152 pid_t pid; 00153 int sock; /* fd to write message when child is dead*/ 00154 struct child *next; 00155 }; 00156 00157 static struct child *children; 00158 00159 #ifdef Q_WS_X11 00160 extern "C" { 00161 int kdeinit_xio_errhandler( Display * ); 00162 int kdeinit_x_errhandler( Display *, XErrorEvent *err ); 00163 } 00164 #endif 00165 00166 #ifdef KDEINIT_OOM_PROTECT 00167 static int oom_pipe = -1; 00168 #endif 00169 00170 /* 00171 * Clean up the file descriptor table by closing all file descriptors 00172 * that are still open. 00173 * 00174 * This function is called very early in the main() function, so that 00175 * we don't leak anything that was leaked to us. 00176 */ 00177 static void cleanup_fds() 00178 { 00179 int maxfd = FD_SETSIZE; 00180 struct rlimit rl; 00181 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) 00182 maxfd = rl.rlim_max; 00183 for (int fd = 3; fd < maxfd; ++fd) 00184 { 00185 #ifdef KDEINIT_OOM_PROTECT 00186 if( fd != oom_pipe ) 00187 #endif 00188 close(fd); 00189 } 00190 } 00191 00192 /* 00193 * Close fd's which are only useful for the parent process. 00194 * Restore default signal handlers. 00195 */ 00196 static void close_fds() 00197 { 00198 while (struct child *child = children) { 00199 close(child->sock); 00200 children = child->next; 00201 free(child); 00202 } 00203 00204 if (d.deadpipe[0] != -1) 00205 { 00206 close(d.deadpipe[0]); 00207 d.deadpipe[0] = -1; 00208 } 00209 00210 if (d.deadpipe[1] != -1) 00211 { 00212 close(d.deadpipe[1]); 00213 d.deadpipe[1] = -1; 00214 } 00215 00216 if (d.initpipe[0] != -1) 00217 { 00218 close(d.initpipe[0]); 00219 d.initpipe[0] = -1; 00220 } 00221 00222 if (d.initpipe[1] != -1) 00223 { 00224 close(d.initpipe[1]); 00225 d.initpipe[1] = -1; 00226 } 00227 00228 if (d.launcher[0] != -1) 00229 { 00230 close(d.launcher[0]); 00231 d.launcher[0] = -1; 00232 } 00233 if (d.wrapper != -1) 00234 { 00235 close(d.wrapper); 00236 d.wrapper = -1; 00237 } 00238 if (d.accepted_fd != -1) 00239 { 00240 close(d.accepted_fd); 00241 d.accepted_fd = -1; 00242 } 00243 #ifdef Q_WS_X11 00244 if (X11fd >= 0) 00245 { 00246 close(X11fd); 00247 X11fd = -1; 00248 } 00249 if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd ) 00250 { 00251 close(X11_startup_notify_fd); 00252 X11_startup_notify_fd = -1; 00253 } 00254 #endif 00255 00256 KDE_signal(SIGCHLD, SIG_DFL); 00257 KDE_signal(SIGPIPE, SIG_DFL); 00258 } 00259 00260 /* Notify wrapper program that the child it started has finished. */ 00261 static void child_died(pid_t exit_pid, int exit_status) 00262 { 00263 struct child *child, **childptr = &children; 00264 00265 while ((child = *childptr)) 00266 { 00267 if (child->pid == exit_pid) 00268 { 00269 /* Send a message with the return value of the child on the control socket */ 00270 klauncher_header request_header; 00271 long request_data[2]; 00272 request_header.cmd = LAUNCHER_CHILD_DIED; 00273 request_header.arg_length = sizeof(long) * 2; 00274 request_data[0] = exit_pid; 00275 request_data[1] = exit_status; 00276 write(child->sock, &request_header, sizeof(request_header)); 00277 write(child->sock, request_data, request_header.arg_length); 00278 close(child->sock); 00279 00280 *childptr = child->next; 00281 free(child); 00282 return; 00283 } 00284 00285 childptr = &child->next; 00286 } 00287 } 00288 00289 00290 static void exitWithErrorMsg(const QString &errorMsg) 00291 { 00292 fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() ); 00293 QByteArray utf8ErrorMsg = errorMsg.toUtf8(); 00294 d.result = 3; // Error with msg 00295 write(d.fd[1], &d.result, 1); 00296 int l = utf8ErrorMsg.length(); 00297 write(d.fd[1], &l, sizeof(int)); 00298 write(d.fd[1], utf8ErrorMsg.data(), l); 00299 close(d.fd[1]); 00300 exit(255); 00301 } 00302 00303 static void setup_tty( const char* tty ) 00304 { 00305 if( tty == NULL || *tty == '\0' ) 00306 return; 00307 int fd = KDE_open( tty, O_WRONLY ); 00308 if( fd < 0 ) 00309 { 00310 perror( "kdeinit4: could not open() tty" ); 00311 return; 00312 } 00313 if( dup2( fd, STDOUT_FILENO ) < 0 ) 00314 { 00315 perror( "kdeinit4: could not dup2() stdout tty" ); 00316 } 00317 if( dup2( fd, STDERR_FILENO ) < 0 ) 00318 { 00319 perror( "kdeinit4: could not dup2() stderr tty" ); 00320 } 00321 close( fd ); 00322 } 00323 00324 // from kdecore/netwm.cpp 00325 static int get_current_desktop( Display* disp ) 00326 { 00327 int desktop = 0; // no desktop by default 00328 #ifdef Q_WS_X11 // Only X11 supports multiple desktops 00329 Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False ); 00330 Atom type_ret; 00331 int format_ret; 00332 unsigned char *data_ret; 00333 unsigned long nitems_ret, unused; 00334 if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop, 00335 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret ) 00336 == Success) 00337 { 00338 if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1) 00339 desktop = *((long *) data_ret) + 1; 00340 if (data_ret) 00341 XFree ((char*) data_ret); 00342 } 00343 #endif 00344 return desktop; 00345 } 00346 00347 // var has to be e.g. "DISPLAY=", i.e. with = 00348 const char* get_env_var( const char* var, int envc, const char* envs ) 00349 { 00350 if( envc > 0 ) 00351 { // get the var from envs 00352 const char* env_l = envs; 00353 int ln = strlen( var ); 00354 for (int i = 0; i < envc; i++) 00355 { 00356 if( strncmp( env_l, var, ln ) == 0 ) 00357 return env_l + ln; 00358 while(*env_l != 0) env_l++; 00359 env_l++; 00360 } 00361 } 00362 return NULL; 00363 } 00364 00365 #ifdef Q_WS_X11 00366 static void init_startup_info( KStartupInfoId& id, const char* bin, 00367 int envc, const char* envs ) 00368 { 00369 const char* dpy = get_env_var( DISPLAY"=", envc, envs ); 00370 // this may be called in a child, so it can't use display open using X11display 00371 // also needed for multihead 00372 X11_startup_notify_display = XOpenDisplay( dpy ); 00373 if( X11_startup_notify_display == NULL ) 00374 return; 00375 X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display ); 00376 KStartupInfoData data; 00377 int desktop = get_current_desktop( X11_startup_notify_display ); 00378 data.setDesktop( desktop ); 00379 data.setBin(QFile::decodeName(bin)); 00380 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data ); 00381 XFlush( X11_startup_notify_display ); 00382 } 00383 00384 static void complete_startup_info( KStartupInfoId& id, pid_t pid ) 00385 { 00386 if( X11_startup_notify_display == NULL ) 00387 return; 00388 if( pid == 0 ) // failure 00389 KStartupInfo::sendFinishX( X11_startup_notify_display, id ); 00390 else 00391 { 00392 KStartupInfoData data; 00393 data.addPid( pid ); 00394 data.setHostname(); 00395 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data ); 00396 } 00397 XCloseDisplay( X11_startup_notify_display ); 00398 X11_startup_notify_display = NULL; 00399 X11_startup_notify_fd = -1; 00400 } 00401 #endif 00402 00403 QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops ) 00404 { 00405 QStringList paths; 00406 const QRegExp pathSepRegExp(QString::fromLatin1("[:\b]")); 00407 if( envc > 0 ) /* use the passed environment */ 00408 { 00409 const char* path = get_env_var( "PATH=", envc, envs ); 00410 if( path != NULL ) 00411 paths = QFile::decodeName(path).split(pathSepRegExp); 00412 } else { 00413 paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSepRegExp, QString::KeepEmptyParts); 00414 } 00415 QString execpath = 00416 s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":"))); 00417 if (avoid_loops && !execpath.isEmpty()) { 00418 const int pos = execpath.lastIndexOf(QLatin1Char('/')); 00419 const QString bin_path = execpath.left(pos); 00420 for( QStringList::Iterator it = paths.begin(); 00421 it != paths.end(); 00422 ++it ) { 00423 if( *it == bin_path || *it == bin_path + QLatin1Char('/')) { 00424 paths.erase( it ); 00425 break; // --> 00426 } 00427 } 00428 execpath = s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":"))); 00429 } 00430 return QFile::encodeName(execpath); 00431 } 00432 00433 #ifdef KDEINIT_OOM_PROTECT 00434 static void oom_protect_sighandler( int ) { 00435 } 00436 00437 static void reset_oom_protect() { 00438 if( oom_pipe <= 0 ) 00439 return; 00440 struct sigaction act, oldact; 00441 act.sa_handler = oom_protect_sighandler; 00442 act.sa_flags = 0; 00443 sigemptyset( &act.sa_mask ); 00444 sigaction( SIGUSR1, &act, &oldact ); 00445 sigset_t sigs, oldsigs; 00446 sigemptyset( &sigs ); 00447 sigaddset( &sigs, SIGUSR1 ); 00448 sigprocmask( SIG_BLOCK, &sigs, &oldsigs ); 00449 pid_t pid = getpid(); 00450 if( write( oom_pipe, &pid, sizeof( pid_t )) > 0 ) { 00451 sigsuspend( &oldsigs ); // wait for the signal to come 00452 } else { 00453 #ifndef NDEBUG 00454 fprintf( stderr, "Failed to reset OOM protection: %d\n", pid ); 00455 #endif 00456 } 00457 sigprocmask( SIG_SETMASK, &oldsigs, NULL ); 00458 sigaction( SIGUSR1, &oldact, NULL ); 00459 close( oom_pipe ); 00460 oom_pipe = -1; 00461 } 00462 #else 00463 static void reset_oom_protect() { 00464 } 00465 #endif 00466 00467 static pid_t launch(int argc, const char *_name, const char *args, 00468 const char *cwd=0, int envc=0, const char *envs=0, 00469 bool reset_env = false, 00470 const char *tty=0, bool avoid_loops = false, 00471 const char* startup_id_str = "0" ) // krazy:exclude=doublequote_chars 00472 { 00473 QString lib; 00474 QByteArray name; 00475 QByteArray exec; 00476 QString libpath; 00477 QByteArray execpath; 00478 00479 if (_name[0] != '/') { 00480 name = _name; 00481 lib = QFile::decodeName(name); 00482 exec = name; 00483 KLibrary klib(QLatin1String("libkdeinit4_") + lib, *s_instance ); 00484 libpath = klib.fileName(); 00485 if( libpath.isEmpty()) { 00486 KLibrary klib(lib, *s_instance); 00487 libpath = klib.fileName(); 00488 } 00489 execpath = execpath_avoid_loops(exec, envc, envs, avoid_loops); 00490 } else { 00491 name = _name; 00492 lib = QFile::decodeName(name); 00493 name = name.mid(name.lastIndexOf('/') + 1); 00494 exec = _name; 00495 if (lib.endsWith(QLatin1String(".so"))) 00496 libpath = lib; 00497 else { 00498 // try to match an absolute path to an executable binary (either in bin/ or in libexec/) 00499 // to a kdeinit module in the same prefix 00500 if( lib.contains( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ))) { 00501 libpath = QString( lib ).replace( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ), 00502 QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so"); 00503 } else if( lib.contains( QLatin1String( "/bin/" ))) { 00504 libpath = QString( lib ).replace( QLatin1String( "/bin/" ), 00505 QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so"); 00506 } 00507 // Don't confuse the user with "Could not load libkdeinit4_foo.so" if it doesn't exist 00508 if (!QFile::exists(libpath)) { 00509 libpath.clear(); 00510 } 00511 execpath = exec; 00512 } 00513 } 00514 #ifndef NDEBUG 00515 fprintf(stderr,"kdeinit4: preparing to launch %s\n", libpath.isEmpty() 00516 ? execpath.constData() : libpath.toUtf8().constData()); 00517 #endif 00518 if (!args) { 00519 argc = 1; 00520 } 00521 00522 if (0 > pipe(d.fd)) 00523 { 00524 perror("kdeinit4: pipe() failed"); 00525 d.result = 3; 00526 d.errorMsg = i18n("Unable to start new process.\n" 00527 "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.").toUtf8(); 00528 d.fork = 0; 00529 return d.fork; 00530 } 00531 00532 #ifdef Q_WS_X11 00533 KStartupInfoId startup_id; 00534 startup_id.initId( startup_id_str ); 00535 if( !startup_id.none()) 00536 init_startup_info( startup_id, name, envc, envs ); 00537 #endif 00538 // find out this path before forking, doing it afterwards 00539 // crashes on some platforms, notably OSX 00540 #ifdef Q_WS_MAC 00541 const QString bundlepath = s_instance->dirs()->findExe(QFile::decodeName(execpath)); 00542 #endif 00543 00544 d.errorMsg = 0; 00545 d.fork = fork(); 00546 switch(d.fork) { 00547 case -1: 00548 perror("kdeinit4: fork() failed"); 00549 d.result = 3; 00550 d.errorMsg = i18n("Unable to create new process.\n" 00551 "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.").toUtf8(); 00552 close(d.fd[0]); 00553 close(d.fd[1]); 00554 d.fork = 0; 00555 break; 00556 case 0: 00557 { 00559 close(d.fd[0]); 00560 close_fds(); 00561 reset_oom_protect(); 00562 00563 // Try to chdir, either to the requested directory or to the user's document path by default. 00564 // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist, 00565 // we still want to execute `foo` even if the chdir() failed. 00566 if (cwd && *cwd) { 00567 (void)chdir(cwd); 00568 } 00569 00570 if( reset_env ) // KWRAPPER/SHELL 00571 { 00572 00573 QList<QByteArray> unset_envs; 00574 for( int tmp_env_count = 0; 00575 environ[tmp_env_count]; 00576 tmp_env_count++) 00577 unset_envs.append( environ[ tmp_env_count ] ); 00578 foreach(const QByteArray &tmp, unset_envs) 00579 { 00580 int pos = tmp.indexOf( '=' ); 00581 if( pos >= 0 ) 00582 unsetenv( tmp.left( pos )); 00583 } 00584 } 00585 00586 for (int i = 0; i < envc; i++) 00587 { 00588 putenv((char *)envs); 00589 while(*envs != 0) envs++; 00590 envs++; 00591 } 00592 00593 #ifdef Q_WS_X11 00594 if( startup_id.none()) 00595 KStartupInfo::resetStartupEnv(); 00596 else 00597 startup_id.setupStartupEnv(); 00598 #endif 00599 { 00600 int r; 00601 QByteArray procTitle; 00602 d.argv = (char **) malloc(sizeof(char *) * (argc+1)); 00603 d.argv[0] = (char *) _name; 00604 #ifdef Q_WS_MAC 00605 QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0])); 00606 if (!argvexe.isEmpty()) { 00607 QByteArray cstr = argvexe.toLocal8Bit(); 00608 kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data(); 00609 d.argv[0] = strdup(cstr.data()); 00610 } 00611 #endif 00612 for (int i = 1; i < argc; i++) 00613 { 00614 d.argv[i] = (char *) args; 00615 procTitle += ' '; 00616 procTitle += (char *) args; 00617 while(*args != 0) args++; 00618 args++; 00619 } 00620 d.argv[argc] = 0; 00621 00622 #ifndef SKIP_PROCTITLE 00623 00624 #ifdef Q_OS_LINUX 00625 /* set the process name, so that killall works like intended */ 00626 r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0); 00627 if ( r == 0 ) 00628 proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00629 else 00630 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00631 #else 00632 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00633 #endif 00634 #endif 00635 } 00636 00637 if (libpath.isEmpty() && execpath.isEmpty()) 00638 { 00639 QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name)); 00640 exitWithErrorMsg(errorMsg); 00641 } 00642 00643 00644 if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty()) 00645 libpath.truncate(0); 00646 00647 QLibrary l(libpath); 00648 00649 if ( !libpath.isEmpty() ) 00650 { 00651 if (!l.load() || !l.isLoaded() ) 00652 { 00653 QString ltdlError (l.errorString()); 00654 if (execpath.isEmpty()) 00655 { 00656 // Error 00657 QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError); 00658 exitWithErrorMsg(errorMsg); 00659 } 00660 else 00661 { 00662 // Print warning 00663 fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib), 00664 qPrintable(ltdlError) ); 00665 } 00666 } 00667 } 00668 if (!l.isLoaded()) 00669 { 00670 d.result = 2; // Try execing 00671 write(d.fd[1], &d.result, 1); 00672 00673 // We set the close on exec flag. 00674 // Closing of d.fd[1] indicates that the execvp succeeded! 00675 fcntl(d.fd[1], F_SETFD, FD_CLOEXEC); 00676 00677 setup_tty( tty ); 00678 00679 QByteArray executable = execpath; 00680 #ifdef Q_WS_MAC 00681 if (!bundlepath.isEmpty()) 00682 executable = QFile::encodeName(bundlepath); 00683 #endif 00684 00685 if (!executable.isEmpty()) 00686 execvp(executable, d.argv); 00687 00688 d.result = 1; // Error 00689 write(d.fd[1], &d.result, 1); 00690 close(d.fd[1]); 00691 exit(255); 00692 } 00693 00694 void * sym = l.resolve( "kdeinitmain"); 00695 if (!sym ) 00696 { 00697 sym = l.resolve( "kdemain" ); 00698 if ( !sym ) 00699 { 00700 QString ltdlError = l.errorString(); 00701 fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) ); 00702 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2", 00703 libpath, ltdlError); 00704 exitWithErrorMsg(errorMsg); 00705 } 00706 } 00707 00708 d.result = 0; // Success 00709 write(d.fd[1], &d.result, 1); 00710 close(d.fd[1]); 00711 00712 d.func = (int (*)(int, char *[])) sym; 00713 if (d.debug_wait) 00714 { 00715 fprintf(stderr, "kdeinit4: Suspending process\n" 00716 "kdeinit4: 'gdb kdeinit4 %d' to debug\n" 00717 "kdeinit4: 'kill -SIGCONT %d' to continue\n", 00718 getpid(), getpid()); 00719 kill(getpid(), SIGSTOP); 00720 } 00721 else 00722 { 00723 setup_tty( tty ); 00724 } 00725 00726 exit( d.func(argc, d.argv)); /* Launch! */ 00727 00728 break; 00729 } 00730 default: 00732 close(d.fd[1]); 00733 bool exec = false; 00734 for(;;) 00735 { 00736 d.n = read(d.fd[0], &d.result, 1); 00737 if (d.n == 1) 00738 { 00739 if (d.result == 2) 00740 { 00741 #ifndef NDEBUG 00742 //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n"); 00743 #endif 00744 exec = true; 00745 continue; 00746 } 00747 if (d.result == 3) 00748 { 00749 int l = 0; 00750 d.n = read(d.fd[0], &l, sizeof(int)); 00751 if (d.n == sizeof(int)) 00752 { 00753 QByteArray tmp; 00754 tmp.resize(l+1); 00755 d.n = read(d.fd[0], tmp.data(), l); 00756 tmp[l] = 0; 00757 if (d.n == l) 00758 d.errorMsg = tmp; 00759 } 00760 } 00761 // Finished 00762 break; 00763 } 00764 if (d.n == -1) 00765 { 00766 if (errno == ECHILD) { // a child died. 00767 continue; 00768 } 00769 if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read 00770 continue; 00771 } 00772 } 00773 if (d.n == 0) 00774 { 00775 if (exec) { 00776 d.result = 0; 00777 } else { 00778 fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData()); 00779 perror("kdeinit4: Pipe closed unexpectedly"); 00780 d.result = 1; // Error 00781 } 00782 break; 00783 } 00784 perror("kdeinit4: Error reading from pipe"); 00785 d.result = 1; // Error 00786 break; 00787 } 00788 close(d.fd[0]); 00789 } 00790 #ifdef Q_WS_X11 00791 if( !startup_id.none()) 00792 { 00793 if( d.fork && d.result == 0 ) // launched successfully 00794 complete_startup_info( startup_id, d.fork ); 00795 else // failure, cancel ASN 00796 complete_startup_info( startup_id, 0 ); 00797 } 00798 #endif 00799 return d.fork; 00800 } 00801 00802 extern "C" { 00803 00804 static void sig_child_handler(int) 00805 { 00806 /* 00807 * Write into the pipe of death. 00808 * This way we are sure that we return from the select() 00809 * 00810 * A signal itself causes select to return as well, but 00811 * this creates a race-condition in case the signal arrives 00812 * just before we enter the select. 00813 */ 00814 char c = 0; 00815 write(d.deadpipe[1], &c, 1); 00816 } 00817 00818 } 00819 00820 static void init_signals() 00821 { 00822 struct sigaction act; 00823 long options; 00824 00825 if (pipe(d.deadpipe) != 0) 00826 { 00827 perror("kdeinit4: Aborting. Can not create pipe"); 00828 exit(255); 00829 } 00830 00831 options = fcntl(d.deadpipe[0], F_GETFL); 00832 if (options == -1) 00833 { 00834 perror("kdeinit4: Aborting. Can not make pipe non-blocking"); 00835 exit(255); 00836 } 00837 00838 if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1) 00839 { 00840 perror("kdeinit4: Aborting. Can not make pipe non-blocking"); 00841 exit(255); 00842 } 00843 00844 /* 00845 * A SIGCHLD handler is installed which sends a byte into the 00846 * pipe of death. This is to ensure that a dying child causes 00847 * an exit from select(). 00848 */ 00849 act.sa_handler=sig_child_handler; 00850 sigemptyset(&(act.sa_mask)); 00851 sigaddset(&(act.sa_mask), SIGCHLD); 00852 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L); 00853 act.sa_flags = SA_NOCLDSTOP; 00854 00855 // CC: take care of SunOS which automatically restarts interrupted system 00856 // calls (and thus does not have SA_RESTART) 00857 00858 #ifdef SA_RESTART 00859 act.sa_flags |= SA_RESTART; 00860 #endif 00861 sigaction( SIGCHLD, &act, 0L); 00862 00863 act.sa_handler=SIG_IGN; 00864 sigemptyset(&(act.sa_mask)); 00865 sigaddset(&(act.sa_mask), SIGPIPE); 00866 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L); 00867 act.sa_flags = 0; 00868 sigaction( SIGPIPE, &act, 0L); 00869 } 00870 00871 static void init_kdeinit_socket() 00872 { 00873 struct sockaddr_un sa; 00874 kde_socklen_t socklen; 00875 long options; 00876 const QByteArray home_dir = qgetenv("HOME"); 00877 int max_tries = 10; 00878 if (home_dir.isEmpty()) 00879 { 00880 fprintf(stderr, "kdeinit4: Aborting. $HOME not set!"); 00881 exit(255); 00882 } 00883 if (chdir(home_dir) != 0) { 00884 fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData()); 00885 exit(255); 00886 } 00887 00888 { 00889 QByteArray path = home_dir; 00890 QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); 00891 if (access(path.data(), R_OK|W_OK)) 00892 { 00893 if (errno == ENOENT) 00894 { 00895 fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data()); 00896 exit(255); 00897 } 00898 else if (readOnly.isEmpty()) 00899 { 00900 fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data()); 00901 exit(255); 00902 } 00903 } 00904 #if 0 // obsolete in kde4. Should we check writing to another file instead? 00905 path = qgetenv("ICEAUTHORITY"); 00906 if (path.isEmpty()) 00907 { 00908 path = home_dir; 00909 path += "/.ICEauthority"; 00910 } 00911 if (access(path.data(), R_OK|W_OK) && (errno != ENOENT)) 00912 { 00913 fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data()); 00914 exit(255); 00915 } 00916 #endif 00917 } 00918 00923 if (access(sock_file, W_OK) == 0) 00924 { 00925 int s; 00926 struct sockaddr_un server; 00927 00928 // fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n"); 00929 /* 00930 * create the socket stream 00931 */ 00932 s = socket(PF_UNIX, SOCK_STREAM, 0); 00933 if (s < 0) 00934 { 00935 perror("socket() failed"); 00936 exit(255); 00937 } 00938 server.sun_family = AF_UNIX; 00939 strcpy(server.sun_path, sock_file); 00940 socklen = sizeof(server); 00941 00942 if(connect(s, (struct sockaddr *)&server, socklen) == 0) 00943 { 00944 fprintf(stderr, "kdeinit4: Shutting down running client.\n"); 00945 klauncher_header request_header; 00946 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT; 00947 request_header.arg_length = 0; 00948 write(s, &request_header, sizeof(request_header)); 00949 sleep(1); // Give it some time 00950 } 00951 close(s); 00952 } 00953 00955 unlink(sock_file); 00956 00958 d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0); 00959 if (d.wrapper < 0) 00960 { 00961 perror("kdeinit4: Aborting. socket() failed"); 00962 exit(255); 00963 } 00964 00965 options = fcntl(d.wrapper, F_GETFL); 00966 if (options == -1) 00967 { 00968 perror("kdeinit4: Aborting. Can not make socket non-blocking"); 00969 close(d.wrapper); 00970 exit(255); 00971 } 00972 00973 if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1) 00974 { 00975 perror("kdeinit4: Aborting. Can not make socket non-blocking"); 00976 close(d.wrapper); 00977 exit(255); 00978 } 00979 00980 while (1) { 00982 socklen = sizeof(sa); 00983 memset(&sa, 0, socklen); 00984 sa.sun_family = AF_UNIX; 00985 strcpy(sa.sun_path, sock_file); 00986 if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0) 00987 { 00988 if (max_tries == 0) { 00989 perror("kdeinit4: Aborting. bind() failed"); 00990 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file); 00991 close(d.wrapper); 00992 exit(255); 00993 } 00994 max_tries--; 00995 } else 00996 break; 00997 } 00998 01000 if (chmod(sock_file, 0600) != 0) 01001 { 01002 perror("kdeinit4: Aborting. Can not set permissions on socket"); 01003 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file); 01004 unlink(sock_file); 01005 close(d.wrapper); 01006 exit(255); 01007 } 01008 01009 if(listen(d.wrapper, SOMAXCONN) < 0) 01010 { 01011 perror("kdeinit4: Aborting. listen() failed"); 01012 unlink(sock_file); 01013 close(d.wrapper); 01014 exit(255); 01015 } 01016 } 01017 01018 /* 01019 * Read 'len' bytes from 'sock' into buffer. 01020 * returns 0 on success, -1 on failure. 01021 */ 01022 static int read_socket(int sock, char *buffer, int len) 01023 { 01024 ssize_t result; 01025 int bytes_left = len; 01026 while ( bytes_left > 0) 01027 { 01028 result = read(sock, buffer, bytes_left); 01029 if (result > 0) 01030 { 01031 buffer += result; 01032 bytes_left -= result; 01033 } 01034 else if (result == 0) 01035 return -1; 01036 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN)) 01037 return -1; 01038 } 01039 return 0; 01040 } 01041 01042 static void start_klauncher() 01043 { 01044 if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) { 01045 perror("kdeinit4: socketpair() failed"); 01046 exit(255); 01047 } 01048 char args[32]; 01049 strcpy(args, "--fd="); 01050 sprintf(args + 5, "%d", d.launcher[1]); 01051 d.launcher_pid = launch( 2, "klauncher", args ); 01052 close(d.launcher[1]); 01053 #ifndef NDEBUG 01054 fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n", 01055 (long) d.launcher_pid, d.result); 01056 #endif 01057 } 01058 01059 static void launcher_died() 01060 { 01061 if (!d.launcher_ok) 01062 { 01063 /* This is bad. */ 01064 fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n"); 01065 ::exit(255); 01066 return; 01067 } 01068 01069 // KLauncher died... restart 01070 #ifndef NDEBUG 01071 fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n"); 01072 #endif 01073 // Make sure it's really dead. 01074 if (d.launcher_pid) 01075 { 01076 kill(d.launcher_pid, SIGKILL); 01077 sleep(1); // Give it some time 01078 } 01079 01080 d.launcher_ok = false; 01081 d.launcher_pid = 0; 01082 close(d.launcher[0]); 01083 d.launcher[0] = -1; 01084 01085 start_klauncher(); 01086 } 01087 01088 static bool handle_launcher_request(int sock, const char *who) 01089 { 01090 (void)who; // for NDEBUG 01091 01092 klauncher_header request_header; 01093 char *request_data = 0L; 01094 int result = read_socket(sock, (char *) &request_header, sizeof(request_header)); 01095 if (result != 0) 01096 { 01097 return false; 01098 } 01099 01100 if ( request_header.arg_length != 0 ) 01101 { 01102 request_data = (char *) malloc(request_header.arg_length); 01103 01104 result = read_socket(sock, request_data, request_header.arg_length); 01105 if (result != 0) 01106 { 01107 free(request_data); 01108 return false; 01109 } 01110 } 01111 01112 //kDebug() << "Got cmd" << request_header.cmd << commandToString(request_header.cmd); 01113 if (request_header.cmd == LAUNCHER_OK) 01114 { 01115 d.launcher_ok = true; 01116 } 01117 else if (request_header.arg_length && 01118 ((request_header.cmd == LAUNCHER_EXEC) || 01119 (request_header.cmd == LAUNCHER_EXT_EXEC) || 01120 (request_header.cmd == LAUNCHER_SHELL ) || 01121 (request_header.cmd == LAUNCHER_KWRAPPER) || 01122 (request_header.cmd == LAUNCHER_EXEC_NEW))) 01123 { 01124 pid_t pid; 01125 klauncher_header response_header; 01126 long response_data; 01127 long l; 01128 memcpy( &l, request_data, sizeof( long )); 01129 int argc = l; 01130 const char *name = request_data + sizeof(long); 01131 const char *args = name + strlen(name) + 1; 01132 const char *cwd = 0; 01133 int envc = 0; 01134 const char *envs = 0; 01135 const char *tty = 0; 01136 int avoid_loops = 0; 01137 const char *startup_id_str = "0"; // krazy:exclude=doublequote_chars 01138 01139 #ifndef NDEBUG 01140 fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n", 01141 commandToString(request_header.cmd), 01142 name, who); 01143 #endif 01144 01145 const char *arg_n = args; 01146 for(int i = 1; i < argc; i++) 01147 { 01148 arg_n = arg_n + strlen(arg_n) + 1; 01149 } 01150 01151 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER ) 01152 { 01153 // Shell or kwrapper 01154 cwd = arg_n; arg_n += strlen(cwd) + 1; 01155 } 01156 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER 01157 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ) 01158 { 01159 memcpy( &l, arg_n, sizeof( long )); 01160 envc = l; 01161 arg_n += sizeof(long); 01162 envs = arg_n; 01163 for(int i = 0; i < envc; i++) 01164 { 01165 arg_n = arg_n + strlen(arg_n) + 1; 01166 } 01167 if( request_header.cmd == LAUNCHER_KWRAPPER ) 01168 { 01169 tty = arg_n; 01170 arg_n += strlen( tty ) + 1; 01171 } 01172 } 01173 01174 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER 01175 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ) 01176 { 01177 memcpy( &l, arg_n, sizeof( long )); 01178 avoid_loops = l; 01179 arg_n += sizeof( long ); 01180 } 01181 01182 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER 01183 || request_header.cmd == LAUNCHER_EXT_EXEC ) 01184 { 01185 startup_id_str = arg_n; 01186 arg_n += strlen( startup_id_str ) + 1; 01187 } 01188 01189 if ((request_header.arg_length > (arg_n - request_data)) && 01190 (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )) 01191 { 01192 // Optional cwd 01193 cwd = arg_n; arg_n += strlen(cwd) + 1; 01194 } 01195 01196 if ((arg_n - request_data) != request_header.arg_length) 01197 { 01198 #ifndef NDEBUG 01199 fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n"); 01200 #endif 01201 free(request_data); 01202 d.debug_wait = false; 01203 return true; // sure? 01204 } 01205 01206 // support for the old a bit broken way of setting DISPLAY for multihead 01207 QByteArray olddisplay = qgetenv(DISPLAY); 01208 QByteArray kdedisplay = qgetenv("KDE_DISPLAY"); 01209 bool reset_display = (! olddisplay.isEmpty() && 01210 ! kdedisplay.isEmpty() && 01211 olddisplay != kdedisplay); 01212 01213 if (reset_display) 01214 setenv(DISPLAY, kdedisplay, true); 01215 01216 pid = launch( argc, name, args, cwd, envc, envs, 01217 request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER, 01218 tty, avoid_loops, startup_id_str ); 01219 01220 if (reset_display) { 01221 unsetenv("KDE_DISPLAY"); 01222 setenv(DISPLAY, olddisplay, true); 01223 } 01224 01225 if (pid && (d.result == 0)) 01226 { 01227 response_header.cmd = LAUNCHER_OK; 01228 response_header.arg_length = sizeof(response_data); 01229 response_data = pid; 01230 write(sock, &response_header, sizeof(response_header)); 01231 write(sock, &response_data, response_header.arg_length); 01232 01233 /* add new child to list */ 01234 struct child *child = (struct child *) malloc(sizeof(struct child)); 01235 child->pid = pid; 01236 child->sock = dup(sock); 01237 child->next = children; 01238 children = child; 01239 } 01240 else 01241 { 01242 int l = d.errorMsg.length(); 01243 if (l) l++; // Include trailing null. 01244 response_header.cmd = LAUNCHER_ERROR; 01245 response_header.arg_length = l; 01246 write(sock, &response_header, sizeof(response_header)); 01247 if (l) 01248 write(sock, d.errorMsg.data(), l); 01249 } 01250 d.debug_wait = false; 01251 } 01252 else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV) 01253 { 01254 const char *env_name; 01255 const char *env_value; 01256 env_name = request_data; 01257 env_value = env_name + strlen(env_name) + 1; 01258 01259 #ifndef NDEBUG 01260 fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who); 01261 #endif 01262 01263 if ( request_header.arg_length != 01264 (int) (strlen(env_name) + strlen(env_value) + 2)) 01265 { 01266 #ifndef NDEBUG 01267 fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n"); 01268 #endif 01269 free(request_data); 01270 return true; // sure? 01271 } 01272 setenv( env_name, env_value, 1); 01273 } 01274 else if (request_header.cmd == LAUNCHER_TERMINATE_KDE) 01275 { 01276 #ifndef NDEBUG 01277 fprintf(stderr,"kdeinit4: terminate KDE.\n"); 01278 #endif 01279 #ifdef Q_WS_X11 01280 kdeinit_xio_errhandler( 0L ); 01281 #endif 01282 } 01283 else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT) 01284 { 01285 #ifndef NDEBUG 01286 fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid()); 01287 #endif 01288 if (d.launcher_pid) { 01289 kill(d.launcher_pid, SIGTERM); 01290 d.launcher_pid = 0; 01291 close(d.launcher[0]); 01292 d.launcher[0] = -1; 01293 } 01294 unlink(sock_file); 01295 if (children) { 01296 close(d.wrapper); 01297 d.wrapper = -1; 01298 #ifndef NDEBUG 01299 fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n"); 01300 #endif 01301 } else { 01302 raise(SIGTERM); 01303 } 01304 } 01305 else if (request_header.cmd == LAUNCHER_DEBUG_WAIT) 01306 { 01307 #ifndef NDEBUG 01308 fprintf(stderr,"kdeinit4: Debug wait activated.\n"); 01309 #endif 01310 d.debug_wait = true; 01311 } 01312 if (request_data) 01313 free(request_data); 01314 return true; 01315 } 01316 01317 static void handle_requests(pid_t waitForPid) 01318 { 01319 int max_sock = d.deadpipe[0]; 01320 if (d.wrapper > max_sock) 01321 max_sock = d.wrapper; 01322 if (d.launcher[0] > max_sock) 01323 max_sock = d.launcher[0]; 01324 #ifdef Q_WS_X11 01325 if (X11fd > max_sock) 01326 max_sock = X11fd; 01327 #endif 01328 max_sock++; 01329 01330 while(1) 01331 { 01332 fd_set rd_set; 01333 fd_set wr_set; 01334 fd_set e_set; 01335 int result; 01336 pid_t exit_pid; 01337 int exit_status; 01338 char c; 01339 01340 /* Flush the pipe of death */ 01341 while( read(d.deadpipe[0], &c, 1) == 1) 01342 {} 01343 01344 /* Handle dying children */ 01345 do { 01346 exit_pid = waitpid(-1, &exit_status, WNOHANG); 01347 if (exit_pid > 0) 01348 { 01349 #ifndef NDEBUG 01350 fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid); 01351 #endif 01352 if (waitForPid && (exit_pid == waitForPid)) 01353 return; 01354 01355 if( WIFEXITED( exit_status )) // fix process return value 01356 exit_status = WEXITSTATUS(exit_status); 01357 else if( WIFSIGNALED(exit_status)) 01358 exit_status = 128 + WTERMSIG( exit_status ); 01359 child_died(exit_pid, exit_status); 01360 01361 if (d.wrapper < 0 && !children) { 01362 #ifndef NDEBUG 01363 fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n", 01364 (long) getpid()); 01365 #endif 01366 raise(SIGTERM); 01367 } 01368 } 01369 } 01370 while( exit_pid > 0); 01371 01372 FD_ZERO(&rd_set); 01373 FD_ZERO(&wr_set); 01374 FD_ZERO(&e_set); 01375 01376 if (d.launcher[0] >= 0) 01377 FD_SET(d.launcher[0], &rd_set); 01378 if (d.wrapper >= 0) 01379 FD_SET(d.wrapper, &rd_set); 01380 FD_SET(d.deadpipe[0], &rd_set); 01381 #ifdef Q_WS_X11 01382 if(X11fd >= 0) FD_SET(X11fd, &rd_set); 01383 #endif 01384 01385 result = select(max_sock, &rd_set, &wr_set, &e_set, 0); 01386 if (result < 0) { 01387 if (errno == EINTR || errno == EAGAIN) 01388 continue; 01389 perror("kdeinit4: Aborting. select() failed"); 01390 return; 01391 } 01392 01393 /* Handle wrapper request */ 01394 if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set)) 01395 { 01396 struct sockaddr_un client; 01397 kde_socklen_t sClient = sizeof(client); 01398 int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient); 01399 if (sock >= 0) 01400 { 01401 d.accepted_fd = sock; 01402 handle_launcher_request(sock, "wrapper"); 01403 close(sock); 01404 d.accepted_fd = -1; 01405 } 01406 } 01407 01408 /* Handle launcher request */ 01409 if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set)) 01410 { 01411 if (!handle_launcher_request(d.launcher[0], "launcher")) 01412 launcher_died(); 01413 if (waitForPid == d.launcher_pid) 01414 return; 01415 } 01416 01417 #ifdef Q_WS_X11 01418 /* Look for incoming X11 events */ 01419 if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) { 01420 if (X11display != 0) { 01421 XEvent event_return; 01422 while (XPending(X11display)) 01423 XNextEvent(X11display, &event_return); 01424 } 01425 } 01426 #endif 01427 } 01428 } 01429 01430 static void kdeinit_library_path() 01431 { 01432 const QStringList ltdl_library_path = 01433 QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(QLatin1Char(':'),QString::SkipEmptyParts); 01434 #ifdef Q_OS_DARWIN 01435 const QByteArray ldlibpath = qgetenv("DYLD_LIBRARY_PATH"); 01436 #else 01437 const QByteArray ldlibpath = qgetenv("LD_LIBRARY_PATH"); 01438 #endif 01439 const QStringList ld_library_path = 01440 QFile::decodeName(ldlibpath).split(QLatin1Char(':'),QString::SkipEmptyParts); 01441 01442 QByteArray extra_path; 01443 const QStringList candidates = s_instance->dirs()->resourceDirs("lib"); 01444 for (QStringList::ConstIterator it = candidates.begin(); 01445 it != candidates.end(); 01446 ++it) 01447 { 01448 QString d = *it; 01449 if (ltdl_library_path.contains(d)) 01450 continue; 01451 if (ld_library_path.contains(d)) 01452 continue; 01453 if (d[d.length()-1] == QLatin1Char('/')) 01454 { 01455 d.truncate(d.length()-1); 01456 if (ltdl_library_path.contains(d)) 01457 continue; 01458 if (ld_library_path.contains(d)) 01459 continue; 01460 } 01461 if ((d == QLatin1String("/lib")) || (d == QLatin1String("/usr/lib"))) 01462 continue; 01463 01464 QByteArray dir = QFile::encodeName(d); 01465 01466 if (access(dir, R_OK)) 01467 continue; 01468 01469 if ( !extra_path.isEmpty()) 01470 extra_path += ':'; 01471 extra_path += dir; 01472 } 01473 01474 // if (!extra_path.isEmpty()) 01475 // lt_dlsetsearchpath(extra_path.data()); 01476 01477 QByteArray display = qgetenv(DISPLAY); 01478 if (display.isEmpty()) 01479 { 01480 #if defined(Q_WS_X11) || defined(Q_WS_QWS) 01481 fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n"); 01482 exit(255); 01483 #endif 01484 } 01485 int i; 01486 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0) 01487 display.truncate(i); 01488 01489 display.replace(':','_'); 01490 #ifdef __APPLE__ 01491 display.replace('/','_'); 01492 #endif 01493 // WARNING, if you change the socket name, adjust kwrapper too 01494 const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display)); 01495 QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", socketFileName, *s_instance)); 01496 if (socketName.length() >= MAX_SOCK_FILE) 01497 { 01498 fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n"); 01499 fprintf(stderr, " '%s'\n", socketName.data()); 01500 exit(255); 01501 } 01502 strcpy(sock_file, socketName.data()); 01503 } 01504 01505 int kdeinit_xio_errhandler( Display *disp ) 01506 { 01507 // disp is 0L when KDE shuts down. We don't want those warnings then. 01508 01509 if ( disp ) 01510 qWarning( "kdeinit4: Fatal IO error: client killed" ); 01511 01512 if (sock_file[0]) 01513 { 01515 unlink(sock_file); 01516 } 01517 01518 // Don't kill our children in suicide mode, they may still be in use 01519 if (d.suicide) 01520 { 01521 if (d.launcher_pid) 01522 kill(d.launcher_pid, SIGTERM); 01523 if (d.kded_pid) 01524 kill(d.kded_pid, SIGTERM); 01525 exit( 0 ); 01526 } 01527 01528 if ( disp ) 01529 qWarning( "kdeinit4: sending SIGHUP to children." ); 01530 01531 /* this should remove all children we started */ 01532 KDE_signal(SIGHUP, SIG_IGN); 01533 kill(0, SIGHUP); 01534 01535 sleep(2); 01536 01537 if ( disp ) 01538 qWarning( "kdeinit4: sending SIGTERM to children." ); 01539 01540 /* and if they don't listen to us, this should work */ 01541 KDE_signal(SIGTERM, SIG_IGN); 01542 kill(0, SIGTERM); 01543 01544 if ( disp ) 01545 qWarning( "kdeinit4: Exit." ); 01546 01547 exit( 0 ); 01548 return 0; 01549 } 01550 01551 #ifdef Q_WS_X11 01552 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err ) 01553 { 01554 #ifndef NDEBUG 01555 char errstr[256]; 01556 // kdeinit almost doesn't use X, and therefore there shouldn't be any X error 01557 XGetErrorText( dpy, err->error_code, errstr, 256 ); 01558 fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n" 01559 " Major opcode: %d\n" 01560 " Minor opcode: %d\n" 01561 " Resource id: 0x%lx\n", 01562 getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid ); 01563 01564 //kDebug() << kBacktrace(); 01565 01566 #else 01567 Q_UNUSED(dpy); 01568 Q_UNUSED(err); 01569 #endif 01570 return 0; 01571 } 01572 #endif 01573 01574 #ifdef Q_WS_X11 01575 // needs to be done sooner than initXconnection() because of also opening 01576 // another X connection for startup notification purposes 01577 static void setupX() 01578 { 01579 XSetIOErrorHandler(kdeinit_xio_errhandler); 01580 XSetErrorHandler(kdeinit_x_errhandler); 01581 /* 01582 Handle the tricky case of running via kdesu/su/sudo/etc. There the usual case 01583 is that kdesu (etc.) creates a file with xauth information, sets XAUTHORITY, 01584 runs the command and removes the xauth file after the command finishes. However, 01585 dbus and kdeinit daemon currently don't clean up properly and keeping running. 01586 Which means that running a KDE app via kdesu the second time talks to kdeinit 01587 with obsolete xauth information, which makes it unable to connect to X or launch 01588 any X11 applications. 01589 Even fixing the cleanup probably wouldn't be sufficient, since it'd be possible to 01590 launch one kdesu session, another one, exit the first one and the app from the second 01591 session would be using kdeinit from the first one. 01592 So the trick here is to duplicate the xauth file to another file in KDE's tmp 01593 location, make the file have a consistent name so that future sessions will use it 01594 as well, point XAUTHORITY there and never remove the file (except for possible 01595 tmp cleanup). 01596 */ 01597 if( !qgetenv( "XAUTHORITY" ).isEmpty()) { 01598 QByteArray display = qgetenv( DISPLAY ); 01599 int i; 01600 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0) 01601 display.truncate(i); 01602 display.replace(':','_'); 01603 #ifdef __APPLE__ 01604 display.replace('/','_'); 01605 #endif 01606 QString xauth = s_instance->dirs()->saveLocation( "tmp" ) + QLatin1String( "xauth-" ) 01607 + QString::number( getuid()) + QLatin1String( "-" ) + QString::fromLocal8Bit( display ); 01608 KSaveFile xauthfile( xauth ); 01609 QFile xauthfrom( QFile::decodeName( qgetenv( "XAUTHORITY" ))); 01610 if( !xauthfrom.open( QFile::ReadOnly ) || !xauthfile.open( QFile::WriteOnly ) 01611 || xauthfile.write( xauthfrom.readAll()) != xauthfrom.size() || !xauthfile.finalize()) { 01612 xauthfile.abort(); 01613 } else { 01614 setenv( "XAUTHORITY", QFile::encodeName( xauth ), true ); 01615 } 01616 } 01617 } 01618 01619 // Borrowed from kdebase/kaudio/kaudioserver.cpp 01620 static int initXconnection() 01621 { 01622 X11display = XOpenDisplay(NULL); 01623 if ( X11display != 0 ) { 01624 XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \ 01625 0, 01626 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)), 01627 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) ); 01628 #ifndef NDEBUG 01629 fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display)); 01630 #endif 01631 int fd = XConnectionNumber( X11display ); 01632 int on = 1; 01633 (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on)); 01634 return fd; 01635 } else 01636 fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \ 01637 "kdeinit4: Might not terminate at end of session.\n"); 01638 01639 return -1; 01640 } 01641 #endif 01642 01643 extern "C" { 01644 01645 static void secondary_child_handler(int) 01646 { 01647 waitpid(-1, 0, WNOHANG); 01648 } 01649 01650 } 01651 01652 int main(int argc, char **argv, char **envp) 01653 { 01654 #ifndef _WIN32_WCE 01655 setlocale (LC_ALL, ""); 01656 setlocale (LC_NUMERIC, "C"); 01657 #endif 01658 01659 pid_t pid; 01660 bool do_fork = true; 01661 int launch_klauncher = 1; 01662 int launch_kded = 1; 01663 int keep_running = 1; 01664 d.suicide = false; 01665 01667 char **safe_argv = (char **) malloc( sizeof(char *) * argc); 01668 for(int i = 0; i < argc; i++) 01669 { 01670 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]); 01671 if (strcmp(safe_argv[i], "--no-klauncher") == 0) 01672 launch_klauncher = 0; 01673 if (strcmp(safe_argv[i], "--no-kded") == 0) 01674 launch_kded = 0; 01675 #ifdef Q_WS_MACX 01676 // make it nofork to match KUniqueApplication, technically command-line incompatible 01677 if (strcmp(safe_argv[i], "--nofork") == 0) 01678 #else 01679 if (strcmp(safe_argv[i], "--no-fork") == 0) 01680 #endif 01681 do_fork = false; 01682 if (strcmp(safe_argv[i], "--suicide") == 0) 01683 d.suicide = true; 01684 if (strcmp(safe_argv[i], "--exit") == 0) 01685 keep_running = 0; 01686 if (strcmp(safe_argv[i], "--version") == 0) 01687 { 01688 printf("Qt: %s\n", qVersion()); 01689 printf("KDE: %s\n", KDE_VERSION_STRING); 01690 exit(0); 01691 } 01692 #ifdef KDEINIT_OOM_PROTECT 01693 if (strcmp(safe_argv[i], "--oom-pipe") == 0 && i+1<argc) 01694 oom_pipe = atol(argv[i+1]); 01695 #endif 01696 if (strcmp(safe_argv[i], "--help") == 0) 01697 { 01698 printf("Usage: kdeinit4 [options]\n"); 01699 // printf(" --no-dcop Do not start dcopserver\n"); 01700 #ifdef Q_WS_MACX 01701 printf(" --nofork Do not fork\n"); 01702 #else 01703 printf(" --no-fork Do not fork\n"); 01704 #endif 01705 // printf(" --no-klauncher Do not start klauncher\n"); 01706 printf(" --no-kded Do not start kded\n"); 01707 printf(" --suicide Terminate when no KDE applications are left running\n"); 01708 printf(" --version Show version information\n"); 01709 // printf(" --exit Terminate when kded has run\n"); 01710 exit(0); 01711 } 01712 } 01713 01714 cleanup_fds(); 01715 01716 // Redirect stdout to stderr. We have no reason to use stdout anyway. 01717 // This minimizes our impact on commands used in pipes. 01718 (void)dup2(2, 1); 01719 01720 if (do_fork) { 01721 #ifdef Q_WS_MACX 01722 mac_fork_and_reexec_self(); 01723 #else 01724 if (pipe(d.initpipe) != 0) { 01725 perror("kdeinit4: pipe failed"); 01726 return 1; 01727 } 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 KDE_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 ; 01741 // then exit; 01742 close(d.initpipe[0]); 01743 d.initpipe[0] = -1; 01744 return 0; 01745 } 01746 close(d.initpipe[0]); 01747 d.initpipe[0] = -1; 01748 #endif 01749 } 01750 01752 if(keep_running) 01753 setsid(); 01754 01756 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration); 01757 01759 #ifndef SKIP_PROCTITLE 01760 proctitle_init(argc, argv, envp); 01761 #endif 01762 01763 kdeinit_library_path(); 01764 // Don't make our instance the global instance 01765 // (do it only after kdeinit_library_path, that one indirectly uses KConfig, 01766 // which seems to be buggy and always use KGlobal instead of the matching KComponentData) 01767 Q_ASSERT(!KGlobal::hasMainComponent()); 01768 // don't change envvars before proctitle_init() 01769 unsetenv("LD_BIND_NOW"); 01770 unsetenv("DYLD_BIND_AT_LAUNCH"); 01771 KApplication::loadedByKdeinit = true; 01772 01773 d.maxname = strlen(argv[0]); 01774 d.launcher_pid = 0; 01775 d.kded_pid = 0; 01776 d.wrapper = -1; 01777 d.accepted_fd = -1; 01778 d.debug_wait = false; 01779 d.launcher_ok = false; 01780 children = NULL; 01781 init_signals(); 01782 #ifdef Q_WS_X11 01783 setupX(); 01784 #endif 01785 01786 if (keep_running) 01787 { 01788 /* 01789 * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper 01790 * requests. 01791 */ 01792 init_kdeinit_socket(); 01793 } 01794 #ifdef Q_WS_X11 01795 if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty()) { 01796 const int extrasCount = sizeof(extra_libs)/sizeof(extra_libs[0]); 01797 for (int i=0; i<extrasCount; i++) { 01798 QString extra = KStandardDirs::locate("lib", QLatin1String(extra_libs[i]), *s_instance); 01799 01800 // can't use KLibLoader here as it would unload the library 01801 // again 01802 if (!extra.isEmpty()) { 01803 QLibrary l(extra); 01804 l.setLoadHints(QLibrary::ExportExternalSymbolsHint); 01805 l.load(); 01806 } 01807 #ifndef NDEBUG 01808 else { 01809 fprintf( stderr, "%s was not found.\n", extra_libs[i] ); 01810 } 01811 #endif 01812 01813 } 01814 } 01815 #endif 01816 if (launch_klauncher) 01817 { 01818 start_klauncher(); 01819 handle_requests(d.launcher_pid); // Wait for klauncher to be ready 01820 } 01821 01822 #ifdef Q_WS_X11 01823 X11fd = initXconnection(); 01824 #endif 01825 01826 { 01827 QFont::initialize(); 01828 #ifdef Q_WS_X11 01829 if (XSupportsLocale ()) 01830 { 01831 // Similar to QApplication::create_xim() 01832 // but we need to use our own display 01833 XOpenIM (X11display, 0, 0, 0); 01834 } 01835 #endif 01836 } 01837 01838 if (launch_kded) 01839 { 01840 setenv("KDED_STARTED_BY_KDEINIT", "1", true); 01841 pid = launch( 1, KDED_EXENAME, 0 ); 01842 unsetenv("KDED_STARTED_BY_KDEINIT"); 01843 #ifndef NDEBUG 01844 fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result); 01845 #endif 01846 d.kded_pid = pid; 01847 handle_requests(pid); 01848 } 01849 01850 for(int i = 1; i < argc; i++) 01851 { 01852 if (safe_argv[i][0] == '+') 01853 { 01854 pid = launch( 1, safe_argv[i]+1, 0); 01855 #ifndef NDEBUG 01856 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result); 01857 #endif 01858 handle_requests(pid); 01859 } 01860 else if (safe_argv[i][0] == '-' 01861 #ifdef KDEINIT_OOM_PROTECT 01862 || isdigit(safe_argv[i][0]) 01863 #endif 01864 ) 01865 { 01866 // Ignore 01867 } 01868 else 01869 { 01870 pid = launch( 1, safe_argv[i], 0 ); 01871 #ifndef NDEBUG 01872 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result); 01873 #endif 01874 } 01875 } 01876 01878 for(int i = 0; i < argc; i++) 01879 { 01880 free(safe_argv[i]); 01881 } 01882 free (safe_argv); 01883 01884 #ifndef SKIP_PROCTITLE 01885 proctitle_set("kdeinit4 Running..."); 01886 #endif 01887 01888 if (!keep_running) 01889 return 0; 01890 01891 if (d.initpipe[1] != -1) 01892 { 01893 char c = 0; 01894 write(d.initpipe[1], &c, 1); // Kdeinit is started. 01895 close(d.initpipe[1]); 01896 d.initpipe[1] = -1; 01897 } 01898 01899 handle_requests(0); 01900 01901 return 0; 01902 } 01903 01904
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:23 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:23 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.