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