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 00478 QString libpath; 00479 QByteArray execpath; 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 00540 d.errorMsg = 0; 00541 d.fork = fork(); 00542 switch(d.fork) { 00543 case -1: 00544 perror("kdeinit4: fork() failed"); 00545 d.result = 3; 00546 d.errorMsg = i18n("Unable to create new process.\n" 00547 "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(); 00548 close(d.fd[0]); 00549 close(d.fd[1]); 00550 d.fork = 0; 00551 break; 00552 case 0: 00553 { 00555 close(d.fd[0]); 00556 close_fds(); 00557 reset_oom_protect(); 00558 00559 // Try to chdir, either to the requested directory or to the user's document path by default. 00560 // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist, 00561 // we still want to execute `foo` even if the chdir() failed. 00562 if (cwd && *cwd) { 00563 (void)chdir(cwd); 00564 } else { 00565 // on Maemo5, documentPath() is on the SD card, setting it as working directory would block 00566 // USB mass storage access 00567 #ifndef Q_WS_MAEMO_5 00568 const QByteArray docPath = QFile::encodeName(KGlobalSettings::documentPath()); 00569 (void)chdir(docPath.constData()); 00570 #endif 00571 } 00572 00573 if( reset_env ) // KWRAPPER/SHELL 00574 { 00575 00576 QList<QByteArray> unset_envs; 00577 for( int tmp_env_count = 0; 00578 environ[tmp_env_count]; 00579 tmp_env_count++) 00580 unset_envs.append( environ[ tmp_env_count ] ); 00581 foreach(const QByteArray &tmp, unset_envs) 00582 { 00583 int pos = tmp.indexOf( '=' ); 00584 if( pos >= 0 ) 00585 unsetenv( tmp.left( pos )); 00586 } 00587 } 00588 00589 for (int i = 0; i < envc; i++) 00590 { 00591 putenv((char *)envs); 00592 while(*envs != 0) envs++; 00593 envs++; 00594 } 00595 00596 #ifdef Q_WS_X11 00597 if( startup_id.none()) 00598 KStartupInfo::resetStartupEnv(); 00599 else 00600 startup_id.setupStartupEnv(); 00601 #endif 00602 { 00603 int r; 00604 QByteArray procTitle; 00605 d.argv = (char **) malloc(sizeof(char *) * (argc+1)); 00606 d.argv[0] = (char *) _name; 00607 #ifdef Q_WS_MAC 00608 QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0])); 00609 if (!argvexe.isEmpty()) { 00610 QByteArray cstr = argvexe.toLocal8Bit(); 00611 kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data(); 00612 d.argv[0] = strdup(cstr.data()); 00613 } 00614 #endif 00615 for (int i = 1; i < argc; i++) 00616 { 00617 d.argv[i] = (char *) args; 00618 procTitle += ' '; 00619 procTitle += (char *) args; 00620 while(*args != 0) args++; 00621 args++; 00622 } 00623 d.argv[argc] = 0; 00624 00625 #ifndef SKIP_PROCTITLE 00626 00627 #ifdef Q_OS_LINUX 00628 /* set the process name, so that killall works like intended */ 00629 r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0); 00630 if ( r == 0 ) 00631 proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00632 else 00633 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00634 #else 00635 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" ); 00636 #endif 00637 #endif 00638 } 00639 00640 if (libpath.isEmpty() && execpath.isEmpty()) 00641 { 00642 QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name)); 00643 exitWithErrorMsg(errorMsg); 00644 } 00645 00646 00647 if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty()) 00648 libpath.truncate(0); 00649 00650 QLibrary l(libpath); 00651 00652 if ( !libpath.isEmpty() ) 00653 { 00654 if (!l.load() || !l.isLoaded() ) 00655 { 00656 QString ltdlError (l.errorString()); 00657 if (execpath.isEmpty()) 00658 { 00659 // Error 00660 QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError); 00661 exitWithErrorMsg(errorMsg); 00662 } 00663 else 00664 { 00665 // Print warning 00666 fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib), 00667 qPrintable(ltdlError) ); 00668 } 00669 } 00670 } 00671 if (!l.isLoaded()) 00672 { 00673 d.result = 2; // Try execing 00674 write(d.fd[1], &d.result, 1); 00675 00676 // We set the close on exec flag. 00677 // Closing of d.fd[1] indicates that the execvp succeeded! 00678 fcntl(d.fd[1], F_SETFD, FD_CLOEXEC); 00679 00680 setup_tty( tty ); 00681 00682 QByteArray executable = execpath; 00683 #ifdef Q_WS_MAC 00684 QString bundlepath = s_instance->dirs()->findExe(QFile::decodeName(executable)); 00685 if (!bundlepath.isEmpty()) 00686 executable = QFile::encodeName(bundlepath); 00687 #endif 00688 00689 if (!executable.isEmpty()) 00690 execvp(executable, d.argv); 00691 00692 d.result = 1; // Error 00693 write(d.fd[1], &d.result, 1); 00694 close(d.fd[1]); 00695 exit(255); 00696 } 00697 00698 void * sym = l.resolve( "kdeinitmain"); 00699 if (!sym ) 00700 { 00701 sym = l.resolve( "kdemain" ); 00702 if ( !sym ) 00703 { 00704 QString ltdlError = l.errorString(); 00705 fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) ); 00706 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2", 00707 libpath, ltdlError); 00708 exitWithErrorMsg(errorMsg); 00709 } 00710 } 00711 00712 d.result = 0; // Success 00713 write(d.fd[1], &d.result, 1); 00714 close(d.fd[1]); 00715 00716 d.func = (int (*)(int, char *[])) sym; 00717 if (d.debug_wait) 00718 { 00719 fprintf(stderr, "kdeinit4: Suspending process\n" 00720 "kdeinit4: 'gdb kdeinit4 %d' to debug\n" 00721 "kdeinit4: 'kill -SIGCONT %d' to continue\n", 00722 getpid(), getpid()); 00723 kill(getpid(), SIGSTOP); 00724 } 00725 else 00726 { 00727 setup_tty( tty ); 00728 } 00729 00730 exit( d.func(argc, d.argv)); /* Launch! */ 00731 00732 break; 00733 } 00734 default: 00736 close(d.fd[1]); 00737 bool exec = false; 00738 for(;;) 00739 { 00740 d.n = read(d.fd[0], &d.result, 1); 00741 if (d.n == 1) 00742 { 00743 if (d.result == 2) 00744 { 00745 #ifndef NDEBUG 00746 //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n"); 00747 #endif 00748 exec = true; 00749 continue; 00750 } 00751 if (d.result == 3) 00752 { 00753 int l = 0; 00754 d.n = read(d.fd[0], &l, sizeof(int)); 00755 if (d.n == sizeof(int)) 00756 { 00757 QByteArray tmp; 00758 tmp.resize(l+1); 00759 d.n = read(d.fd[0], tmp.data(), l); 00760 tmp[l] = 0; 00761 if (d.n == l) 00762 d.errorMsg = tmp; 00763 } 00764 } 00765 // Finished 00766 break; 00767 } 00768 if (d.n == -1) 00769 { 00770 if (errno == ECHILD) { // a child died. 00771 continue; 00772 } 00773 if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read 00774 continue; 00775 } 00776 } 00777 if (d.n == 0) 00778 { 00779 if (exec) { 00780 d.result = 0; 00781 } else { 00782 fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData()); 00783 perror("kdeinit4: Pipe closed unexpectedly"); 00784 d.result = 1; // Error 00785 } 00786 break; 00787 } 00788 perror("kdeinit4: Error reading from pipe"); 00789 d.result = 1; // Error 00790 break; 00791 } 00792 close(d.fd[0]); 00793 } 00794 #ifdef Q_WS_X11 00795 if( !startup_id.none()) 00796 { 00797 if( d.fork && d.result == 0 ) // launched successfully 00798 complete_startup_info( startup_id, d.fork ); 00799 else // failure, cancel ASN 00800 complete_startup_info( startup_id, 0 ); 00801 } 00802 #endif 00803 return d.fork; 00804 } 00805 00806 extern "C" { 00807 00808 static void sig_child_handler(int) 00809 { 00810 /* 00811 * Write into the pipe of death. 00812 * This way we are sure that we return from the select() 00813 * 00814 * A signal itself causes select to return as well, but 00815 * this creates a race-condition in case the signal arrives 00816 * just before we enter the select. 00817 */ 00818 char c = 0; 00819 write(d.deadpipe[1], &c, 1); 00820 } 00821 00822 } 00823 00824 static void init_signals() 00825 { 00826 struct sigaction act; 00827 long options; 00828 00829 if (pipe(d.deadpipe) != 0) 00830 { 00831 perror("kdeinit4: Aborting. Can not create pipe"); 00832 exit(255); 00833 } 00834 00835 options = fcntl(d.deadpipe[0], F_GETFL); 00836 if (options == -1) 00837 { 00838 perror("kdeinit4: Aborting. Can not make pipe non-blocking"); 00839 exit(255); 00840 } 00841 00842 if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1) 00843 { 00844 perror("kdeinit4: Aborting. Can not make pipe non-blocking"); 00845 exit(255); 00846 } 00847 00848 /* 00849 * A SIGCHLD handler is installed which sends a byte into the 00850 * pipe of death. This is to ensure that a dying child causes 00851 * an exit from select(). 00852 */ 00853 act.sa_handler=sig_child_handler; 00854 sigemptyset(&(act.sa_mask)); 00855 sigaddset(&(act.sa_mask), SIGCHLD); 00856 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L); 00857 act.sa_flags = SA_NOCLDSTOP; 00858 00859 // CC: take care of SunOS which automatically restarts interrupted system 00860 // calls (and thus does not have SA_RESTART) 00861 00862 #ifdef SA_RESTART 00863 act.sa_flags |= SA_RESTART; 00864 #endif 00865 sigaction( SIGCHLD, &act, 0L); 00866 00867 act.sa_handler=SIG_IGN; 00868 sigemptyset(&(act.sa_mask)); 00869 sigaddset(&(act.sa_mask), SIGPIPE); 00870 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L); 00871 act.sa_flags = 0; 00872 sigaction( SIGPIPE, &act, 0L); 00873 } 00874 00875 static void init_kdeinit_socket() 00876 { 00877 struct sockaddr_un sa; 00878 kde_socklen_t socklen; 00879 long options; 00880 const QByteArray home_dir = qgetenv("HOME"); 00881 int max_tries = 10; 00882 if (home_dir.isEmpty()) 00883 { 00884 fprintf(stderr, "kdeinit4: Aborting. $HOME not set!"); 00885 exit(255); 00886 } 00887 if (chdir(home_dir) != 0) { 00888 fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData()); 00889 exit(255); 00890 } 00891 00892 { 00893 QByteArray path = home_dir; 00894 QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); 00895 if (access(path.data(), R_OK|W_OK)) 00896 { 00897 if (errno == ENOENT) 00898 { 00899 fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data()); 00900 exit(255); 00901 } 00902 else if (readOnly.isEmpty()) 00903 { 00904 fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data()); 00905 exit(255); 00906 } 00907 } 00908 #if 0 // obsolete in kde4. Should we check writing to another file instead? 00909 path = qgetenv("ICEAUTHORITY"); 00910 if (path.isEmpty()) 00911 { 00912 path = home_dir; 00913 path += "/.ICEauthority"; 00914 } 00915 if (access(path.data(), R_OK|W_OK) && (errno != ENOENT)) 00916 { 00917 fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data()); 00918 exit(255); 00919 } 00920 #endif 00921 } 00922 00927 if (access(sock_file, W_OK) == 0) 00928 { 00929 int s; 00930 struct sockaddr_un server; 00931 00932 // fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n"); 00933 /* 00934 * create the socket stream 00935 */ 00936 s = socket(PF_UNIX, SOCK_STREAM, 0); 00937 if (s < 0) 00938 { 00939 perror("socket() failed"); 00940 exit(255); 00941 } 00942 server.sun_family = AF_UNIX; 00943 strcpy(server.sun_path, sock_file); 00944 socklen = sizeof(server); 00945 00946 if(connect(s, (struct sockaddr *)&server, socklen) == 0) 00947 { 00948 fprintf(stderr, "kdeinit4: Shutting down running client.\n"); 00949 klauncher_header request_header; 00950 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT; 00951 request_header.arg_length = 0; 00952 write(s, &request_header, sizeof(request_header)); 00953 sleep(1); // Give it some time 00954 } 00955 close(s); 00956 } 00957 00959 unlink(sock_file); 00960 00962 d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0); 00963 if (d.wrapper < 0) 00964 { 00965 perror("kdeinit4: Aborting. socket() failed"); 00966 exit(255); 00967 } 00968 00969 options = fcntl(d.wrapper, F_GETFL); 00970 if (options == -1) 00971 { 00972 perror("kdeinit4: Aborting. Can not make socket non-blocking"); 00973 close(d.wrapper); 00974 exit(255); 00975 } 00976 00977 if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1) 00978 { 00979 perror("kdeinit4: Aborting. Can not make socket non-blocking"); 00980 close(d.wrapper); 00981 exit(255); 00982 } 00983 00984 while (1) { 00986 socklen = sizeof(sa); 00987 memset(&sa, 0, socklen); 00988 sa.sun_family = AF_UNIX; 00989 strcpy(sa.sun_path, sock_file); 00990 if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0) 00991 { 00992 if (max_tries == 0) { 00993 perror("kdeinit4: Aborting. bind() failed"); 00994 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file); 00995 close(d.wrapper); 00996 exit(255); 00997 } 00998 max_tries--; 00999 } else 01000 break; 01001 } 01002 01004 if (chmod(sock_file, 0600) != 0) 01005 { 01006 perror("kdeinit4: Aborting. Can not set permissions on socket"); 01007 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file); 01008 unlink(sock_file); 01009 close(d.wrapper); 01010 exit(255); 01011 } 01012 01013 if(listen(d.wrapper, SOMAXCONN) < 0) 01014 { 01015 perror("kdeinit4: Aborting. listen() failed"); 01016 unlink(sock_file); 01017 close(d.wrapper); 01018 exit(255); 01019 } 01020 } 01021 01022 /* 01023 * Read 'len' bytes from 'sock' into buffer. 01024 * returns 0 on success, -1 on failure. 01025 */ 01026 static int read_socket(int sock, char *buffer, int len) 01027 { 01028 ssize_t result; 01029 int bytes_left = len; 01030 while ( bytes_left > 0) 01031 { 01032 result = read(sock, buffer, bytes_left); 01033 if (result > 0) 01034 { 01035 buffer += result; 01036 bytes_left -= result; 01037 } 01038 else if (result == 0) 01039 return -1; 01040 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN)) 01041 return -1; 01042 } 01043 return 0; 01044 } 01045 01046 static void start_klauncher() 01047 { 01048 if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) { 01049 perror("kdeinit4: socketpair() failed"); 01050 exit(255); 01051 } 01052 char args[32]; 01053 strcpy(args, "--fd="); 01054 sprintf(args + 5, "%d", d.launcher[1]); 01055 d.launcher_pid = launch( 2, "klauncher", args ); 01056 close(d.launcher[1]); 01057 #ifndef NDEBUG 01058 fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n", 01059 (long) d.launcher_pid, d.result); 01060 #endif 01061 } 01062 01063 static void launcher_died() 01064 { 01065 if (!d.launcher_ok) 01066 { 01067 /* This is bad. */ 01068 fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n"); 01069 ::exit(255); 01070 return; 01071 } 01072 01073 // KLauncher died... restart 01074 #ifndef NDEBUG 01075 fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n"); 01076 #endif 01077 // Make sure it's really dead. 01078 if (d.launcher_pid) 01079 { 01080 kill(d.launcher_pid, SIGKILL); 01081 sleep(1); // Give it some time 01082 } 01083 01084 d.launcher_ok = false; 01085 d.launcher_pid = 0; 01086 close(d.launcher[0]); 01087 d.launcher[0] = -1; 01088 01089 start_klauncher(); 01090 } 01091 01092 static bool handle_launcher_request(int sock, const char *who) 01093 { 01094 (void)who; // for NDEBUG 01095 01096 klauncher_header request_header; 01097 char *request_data = 0L; 01098 int result = read_socket(sock, (char *) &request_header, sizeof(request_header)); 01099 if (result != 0) 01100 { 01101 return false; 01102 } 01103 01104 if ( request_header.arg_length != 0 ) 01105 { 01106 request_data = (char *) malloc(request_header.arg_length); 01107 01108 result = read_socket(sock, request_data, request_header.arg_length); 01109 if (result != 0) 01110 { 01111 free(request_data); 01112 return false; 01113 } 01114 } 01115 01116 //kDebug() << "Got cmd" << request_header.cmd << commandToString(request_header.cmd); 01117 if (request_header.cmd == LAUNCHER_OK) 01118 { 01119 d.launcher_ok = true; 01120 } 01121 else if (request_header.arg_length && 01122 ((request_header.cmd == LAUNCHER_EXEC) || 01123 (request_header.cmd == LAUNCHER_EXT_EXEC) || 01124 (request_header.cmd == LAUNCHER_SHELL ) || 01125 (request_header.cmd == LAUNCHER_KWRAPPER) || 01126 (request_header.cmd == LAUNCHER_EXEC_NEW))) 01127 { 01128 pid_t pid; 01129 klauncher_header response_header; 01130 long response_data; 01131 long l; 01132 memcpy( &l, request_data, sizeof( long )); 01133 int argc = l; 01134 const char *name = request_data + sizeof(long); 01135 const char *args = name + strlen(name) + 1; 01136 const char *cwd = 0; 01137 int envc = 0; 01138 const char *envs = 0; 01139 const char *tty = 0; 01140 int avoid_loops = 0; 01141 const char *startup_id_str = "0"; // krazy:exclude=doublequote_chars 01142 01143 #ifndef NDEBUG 01144 fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n", 01145 commandToString(request_header.cmd), 01146 name, who); 01147 #endif 01148 01149 const char *arg_n = args; 01150 for(int i = 1; i < argc; i++) 01151 { 01152 arg_n = arg_n + strlen(arg_n) + 1; 01153 } 01154 01155 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER ) 01156 { 01157 // Shell or kwrapper 01158 cwd = arg_n; arg_n += strlen(cwd) + 1; 01159 } 01160 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER 01161 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ) 01162 { 01163 memcpy( &l, arg_n, sizeof( long )); 01164 envc = l; 01165 arg_n += sizeof(long); 01166 envs = arg_n; 01167 for(int i = 0; i < envc; i++) 01168 { 01169 arg_n = arg_n + strlen(arg_n) + 1; 01170 } 01171 if( request_header.cmd == LAUNCHER_KWRAPPER ) 01172 { 01173 tty = arg_n; 01174 arg_n += strlen( tty ) + 1; 01175 } 01176 } 01177 01178 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER 01179 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ) 01180 { 01181 memcpy( &l, arg_n, sizeof( long )); 01182 avoid_loops = l; 01183 arg_n += sizeof( long ); 01184 } 01185 01186 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER 01187 || request_header.cmd == LAUNCHER_EXT_EXEC ) 01188 { 01189 startup_id_str = arg_n; 01190 arg_n += strlen( startup_id_str ) + 1; 01191 } 01192 01193 if ((request_header.arg_length > (arg_n - request_data)) && 01194 (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )) 01195 { 01196 // Optional cwd 01197 cwd = arg_n; arg_n += strlen(cwd) + 1; 01198 } 01199 01200 if ((arg_n - request_data) != request_header.arg_length) 01201 { 01202 #ifndef NDEBUG 01203 fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n"); 01204 #endif 01205 free(request_data); 01206 d.debug_wait = false; 01207 return true; // sure? 01208 } 01209 01210 // support for the old a bit broken way of setting DISPLAY for multihead 01211 QByteArray olddisplay = qgetenv(DISPLAY); 01212 QByteArray kdedisplay = qgetenv("KDE_DISPLAY"); 01213 bool reset_display = (! olddisplay.isEmpty() && 01214 ! kdedisplay.isEmpty() && 01215 olddisplay != kdedisplay); 01216 01217 if (reset_display) 01218 setenv(DISPLAY, kdedisplay, true); 01219 01220 pid = launch( argc, name, args, cwd, envc, envs, 01221 request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER, 01222 tty, avoid_loops, startup_id_str ); 01223 01224 if (reset_display) { 01225 unsetenv("KDE_DISPLAY"); 01226 setenv(DISPLAY, olddisplay, true); 01227 } 01228 01229 if (pid && (d.result == 0)) 01230 { 01231 response_header.cmd = LAUNCHER_OK; 01232 response_header.arg_length = sizeof(response_data); 01233 response_data = pid; 01234 write(sock, &response_header, sizeof(response_header)); 01235 write(sock, &response_data, response_header.arg_length); 01236 01237 /* add new child to list */ 01238 struct child *child = (struct child *) malloc(sizeof(struct child)); 01239 child->pid = pid; 01240 child->sock = dup(sock); 01241 child->next = children; 01242 children = child; 01243 } 01244 else 01245 { 01246 int l = d.errorMsg.length(); 01247 if (l) l++; // Include trailing null. 01248 response_header.cmd = LAUNCHER_ERROR; 01249 response_header.arg_length = l; 01250 write(sock, &response_header, sizeof(response_header)); 01251 if (l) 01252 write(sock, d.errorMsg.data(), l); 01253 } 01254 d.debug_wait = false; 01255 } 01256 else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV) 01257 { 01258 const char *env_name; 01259 const char *env_value; 01260 env_name = request_data; 01261 env_value = env_name + strlen(env_name) + 1; 01262 01263 #ifndef NDEBUG 01264 fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who); 01265 #endif 01266 01267 if ( request_header.arg_length != 01268 (int) (strlen(env_name) + strlen(env_value) + 2)) 01269 { 01270 #ifndef NDEBUG 01271 fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n"); 01272 #endif 01273 free(request_data); 01274 return true; // sure? 01275 } 01276 setenv( env_name, env_value, 1); 01277 } 01278 else if (request_header.cmd == LAUNCHER_TERMINATE_KDE) 01279 { 01280 #ifndef NDEBUG 01281 fprintf(stderr,"kdeinit4: terminate KDE.\n"); 01282 #endif 01283 #ifdef Q_WS_X11 01284 kdeinit_xio_errhandler( 0L ); 01285 #endif 01286 } 01287 else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT) 01288 { 01289 #ifndef NDEBUG 01290 fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid()); 01291 #endif 01292 if (d.launcher_pid) { 01293 kill(d.launcher_pid, SIGTERM); 01294 d.launcher_pid = 0; 01295 close(d.launcher[0]); 01296 d.launcher[0] = -1; 01297 } 01298 unlink(sock_file); 01299 if (children) { 01300 close(d.wrapper); 01301 d.wrapper = -1; 01302 #ifndef NDEBUG 01303 fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n"); 01304 #endif 01305 } else { 01306 raise(SIGTERM); 01307 } 01308 } 01309 else if (request_header.cmd == LAUNCHER_DEBUG_WAIT) 01310 { 01311 #ifndef NDEBUG 01312 fprintf(stderr,"kdeinit4: Debug wait activated.\n"); 01313 #endif 01314 d.debug_wait = true; 01315 } 01316 if (request_data) 01317 free(request_data); 01318 return true; 01319 } 01320 01321 static void handle_requests(pid_t waitForPid) 01322 { 01323 int max_sock = d.deadpipe[0]; 01324 if (d.wrapper > max_sock) 01325 max_sock = d.wrapper; 01326 if (d.launcher[0] > max_sock) 01327 max_sock = d.launcher[0]; 01328 #ifdef Q_WS_X11 01329 if (X11fd > max_sock) 01330 max_sock = X11fd; 01331 #endif 01332 max_sock++; 01333 01334 while(1) 01335 { 01336 fd_set rd_set; 01337 fd_set wr_set; 01338 fd_set e_set; 01339 int result; 01340 pid_t exit_pid; 01341 int exit_status; 01342 char c; 01343 01344 /* Flush the pipe of death */ 01345 while( read(d.deadpipe[0], &c, 1) == 1) 01346 {} 01347 01348 /* Handle dying children */ 01349 do { 01350 exit_pid = waitpid(-1, &exit_status, WNOHANG); 01351 if (exit_pid > 0) 01352 { 01353 #ifndef NDEBUG 01354 fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid); 01355 #endif 01356 if (waitForPid && (exit_pid == waitForPid)) 01357 return; 01358 01359 if( WIFEXITED( exit_status )) // fix process return value 01360 exit_status = WEXITSTATUS(exit_status); 01361 else if( WIFSIGNALED( exit_status )) 01362 exit_status = 128 + WTERMSIG( exit_status ); 01363 child_died(exit_pid, exit_status); 01364 01365 if (d.wrapper < 0 && !children) { 01366 #ifndef NDEBUG 01367 fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n", 01368 (long) getpid()); 01369 #endif 01370 raise(SIGTERM); 01371 } 01372 } 01373 } 01374 while( exit_pid > 0); 01375 01376 FD_ZERO(&rd_set); 01377 FD_ZERO(&wr_set); 01378 FD_ZERO(&e_set); 01379 01380 if (d.launcher[0] >= 0) 01381 FD_SET(d.launcher[0], &rd_set); 01382 if (d.wrapper >= 0) 01383 FD_SET(d.wrapper, &rd_set); 01384 FD_SET(d.deadpipe[0], &rd_set); 01385 #ifdef Q_WS_X11 01386 if(X11fd >= 0) FD_SET(X11fd, &rd_set); 01387 #endif 01388 01389 result = select(max_sock, &rd_set, &wr_set, &e_set, 0); 01390 if (result < 0) { 01391 if (errno == EINTR || errno == EAGAIN) 01392 continue; 01393 perror("kdeinit4: Aborting. select() failed"); 01394 return; 01395 } 01396 01397 /* Handle wrapper request */ 01398 if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set)) 01399 { 01400 struct sockaddr_un client; 01401 kde_socklen_t sClient = sizeof(client); 01402 int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient); 01403 if (sock >= 0) 01404 { 01405 d.accepted_fd = sock; 01406 handle_launcher_request(sock, "wrapper"); 01407 close(sock); 01408 d.accepted_fd = -1; 01409 } 01410 } 01411 01412 /* Handle launcher request */ 01413 if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set)) 01414 { 01415 if (!handle_launcher_request(d.launcher[0], "launcher")) 01416 launcher_died(); 01417 if (waitForPid == d.launcher_pid) 01418 return; 01419 } 01420 01421 #ifdef Q_WS_X11 01422 /* Look for incoming X11 events */ 01423 if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) { 01424 if (X11display != 0) { 01425 XEvent event_return; 01426 while (XPending(X11display)) 01427 XNextEvent(X11display, &event_return); 01428 } 01429 } 01430 #endif 01431 } 01432 } 01433 01434 static void kdeinit_library_path() 01435 { 01436 const QStringList ltdl_library_path = 01437 QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(QLatin1Char(':'),QString::SkipEmptyParts); 01438 #ifdef Q_OS_DARWIN 01439 const QByteArray ldlibpath = qgetenv("DYLD_LIBRARY_PATH"); 01440 #else 01441 const QByteArray ldlibpath = qgetenv("LD_LIBRARY_PATH"); 01442 #endif 01443 const QStringList ld_library_path = 01444 QFile::decodeName(ldlibpath).split(QLatin1Char(':'),QString::SkipEmptyParts); 01445 01446 QByteArray extra_path; 01447 const QStringList candidates = s_instance->dirs()->resourceDirs("lib"); 01448 for (QStringList::ConstIterator it = candidates.begin(); 01449 it != candidates.end(); 01450 ++it) 01451 { 01452 QString d = *it; 01453 if (ltdl_library_path.contains(d)) 01454 continue; 01455 if (ld_library_path.contains(d)) 01456 continue; 01457 if (d[d.length()-1] == QLatin1Char('/')) 01458 { 01459 d.truncate(d.length()-1); 01460 if (ltdl_library_path.contains(d)) 01461 continue; 01462 if (ld_library_path.contains(d)) 01463 continue; 01464 } 01465 if ((d == QLatin1String("/lib")) || (d == QLatin1String("/usr/lib"))) 01466 continue; 01467 01468 QByteArray dir = QFile::encodeName(d); 01469 01470 if (access(dir, R_OK)) 01471 continue; 01472 01473 if ( !extra_path.isEmpty()) 01474 extra_path += ':'; 01475 extra_path += dir; 01476 } 01477 01478 // if (!extra_path.isEmpty()) 01479 // lt_dlsetsearchpath(extra_path.data()); 01480 01481 QByteArray display = qgetenv(DISPLAY); 01482 if (display.isEmpty()) 01483 { 01484 #if defined(Q_WS_X11) || defined(Q_WS_QWS) 01485 fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n"); 01486 exit(255); 01487 #endif 01488 } 01489 int i; 01490 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0) 01491 display.truncate(i); 01492 01493 display.replace(':','_'); 01494 #ifdef __APPLE__ 01495 display.replace('/','_'); 01496 #endif 01497 // WARNING, if you change the socket name, adjust kwrapper too 01498 const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display)); 01499 QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", socketFileName, *s_instance)); 01500 if (socketName.length() >= MAX_SOCK_FILE) 01501 { 01502 fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n"); 01503 fprintf(stderr, " '%s'\n", socketName.data()); 01504 exit(255); 01505 } 01506 strcpy(sock_file, socketName.data()); 01507 } 01508 01509 int kdeinit_xio_errhandler( Display *disp ) 01510 { 01511 // disp is 0L when KDE shuts down. We don't want those warnings then. 01512 01513 if ( disp ) 01514 qWarning( "kdeinit4: Fatal IO error: client killed" ); 01515 01516 if (sock_file[0]) 01517 { 01519 unlink(sock_file); 01520 } 01521 01522 // Don't kill our children in suicide mode, they may still be in use 01523 if (d.suicide) 01524 { 01525 if (d.launcher_pid) 01526 kill(d.launcher_pid, SIGTERM); 01527 if (d.kded_pid) 01528 kill(d.kded_pid, SIGTERM); 01529 exit( 0 ); 01530 } 01531 01532 if ( disp ) 01533 qWarning( "kdeinit4: sending SIGHUP to children." ); 01534 01535 /* this should remove all children we started */ 01536 KDE_signal(SIGHUP, SIG_IGN); 01537 kill(0, SIGHUP); 01538 01539 sleep(2); 01540 01541 if ( disp ) 01542 qWarning( "kdeinit4: sending SIGTERM to children." ); 01543 01544 /* and if they don't listen to us, this should work */ 01545 KDE_signal(SIGTERM, SIG_IGN); 01546 kill(0, SIGTERM); 01547 01548 if ( disp ) 01549 qWarning( "kdeinit4: Exit." ); 01550 01551 exit( 0 ); 01552 return 0; 01553 } 01554 01555 #ifdef Q_WS_X11 01556 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err ) 01557 { 01558 #ifndef NDEBUG 01559 char errstr[256]; 01560 // kdeinit almost doesn't use X, and therefore there shouldn't be any X error 01561 XGetErrorText( dpy, err->error_code, errstr, 256 ); 01562 fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n" 01563 " Major opcode: %d\n" 01564 " Minor opcode: %d\n" 01565 " Resource id: 0x%lx\n", 01566 getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid ); 01567 01568 //kDebug() << kBacktrace(); 01569 01570 #else 01571 Q_UNUSED(dpy); 01572 Q_UNUSED(err); 01573 #endif 01574 return 0; 01575 } 01576 #endif 01577 01578 #ifdef Q_WS_X11 01579 // needs to be done sooner than initXconnection() because of also opening 01580 // another X connection for startup notification purposes 01581 static void setupX() 01582 { 01583 XSetIOErrorHandler(kdeinit_xio_errhandler); 01584 XSetErrorHandler(kdeinit_x_errhandler); 01585 /* 01586 Handle the tricky case of running via kdesu/su/sudo/etc. There the usual case 01587 is that kdesu (etc.) creates a file with xauth information, sets XAUTHORITY, 01588 runs the command and removes the xauth file after the command finishes. However, 01589 dbus and kdeinit daemon currently don't clean up properly and keeping running. 01590 Which means that running a KDE app via kdesu the second time talks to kdeinit 01591 with obsolete xauth information, which makes it unable to connect to X or launch 01592 any X11 applications. 01593 Even fixing the cleanup probably wouldn't be sufficient, since it'd be possible to 01594 launch one kdesu session, another one, exit the first one and the app from the second 01595 session would be using kdeinit from the first one. 01596 So the trick here is to duplicate the xauth file to another file in KDE's tmp 01597 location, make the file have a consistent name so that future sessions will use it 01598 as well, point XAUTHORITY there and never remove the file (except for possible 01599 tmp cleanup). 01600 */ 01601 if( !qgetenv( "XAUTHORITY" ).isEmpty()) { 01602 QByteArray display = qgetenv( DISPLAY ); 01603 int i; 01604 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0) 01605 display.truncate(i); 01606 display.replace(':','_'); 01607 #ifdef __APPLE__ 01608 display.replace('/','_'); 01609 #endif 01610 QString xauth = s_instance->dirs()->saveLocation( "tmp" ) + QLatin1String( "xauth-" ) 01611 + QString::number( getuid()) + QLatin1String( "-" ) + QString::fromLocal8Bit( display ); 01612 KSaveFile xauthfile( xauth ); 01613 QFile xauthfrom( QFile::decodeName( qgetenv( "XAUTHORITY" ))); 01614 if( !xauthfrom.open( QFile::ReadOnly ) || !xauthfile.open( QFile::WriteOnly ) 01615 || xauthfile.write( xauthfrom.readAll()) != xauthfrom.size() || !xauthfile.finalize()) { 01616 xauthfile.abort(); 01617 } else { 01618 setenv( "XAUTHORITY", QFile::encodeName( xauth ), true ); 01619 } 01620 } 01621 } 01622 01623 // Borrowed from kdebase/kaudio/kaudioserver.cpp 01624 static int initXconnection() 01625 { 01626 X11display = XOpenDisplay(NULL); 01627 if ( X11display != 0 ) { 01628 XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \ 01629 0, 01630 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)), 01631 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) ); 01632 #ifndef NDEBUG 01633 fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display)); 01634 #endif 01635 int fd = XConnectionNumber( X11display ); 01636 int on = 1; 01637 (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on)); 01638 return fd; 01639 } else 01640 fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \ 01641 "kdeinit4: Might not terminate at end of session.\n"); 01642 01643 return -1; 01644 } 01645 #endif 01646 01647 extern "C" { 01648 01649 static void secondary_child_handler(int) 01650 { 01651 waitpid(-1, 0, WNOHANG); 01652 } 01653 01654 } 01655 01656 int main(int argc, char **argv, char **envp) 01657 { 01658 #ifndef _WIN32_WCE 01659 setlocale (LC_ALL, ""); 01660 setlocale (LC_NUMERIC, "C"); 01661 #endif 01662 01663 pid_t pid; 01664 bool do_fork = true; 01665 int launch_klauncher = 1; 01666 int launch_kded = 1; 01667 int keep_running = 1; 01668 d.suicide = false; 01669 01671 char **safe_argv = (char **) malloc( sizeof(char *) * argc); 01672 for(int i = 0; i < argc; i++) 01673 { 01674 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]); 01675 if (strcmp(safe_argv[i], "--no-klauncher") == 0) 01676 launch_klauncher = 0; 01677 if (strcmp(safe_argv[i], "--no-kded") == 0) 01678 launch_kded = 0; 01679 #ifdef Q_WS_MACX 01680 // make it nofork to match KUniqueApplication, technically command-line incompatible 01681 if (strcmp(safe_argv[i], "--nofork") == 0) 01682 #else 01683 if (strcmp(safe_argv[i], "--no-fork") == 0) 01684 #endif 01685 do_fork = false; 01686 if (strcmp(safe_argv[i], "--suicide") == 0) 01687 d.suicide = true; 01688 if (strcmp(safe_argv[i], "--exit") == 0) 01689 keep_running = 0; 01690 if (strcmp(safe_argv[i], "--version") == 0) 01691 { 01692 printf("Qt: %s\n", qVersion()); 01693 printf("KDE: %s\n", KDE_VERSION_STRING); 01694 exit(0); 01695 } 01696 #ifdef KDEINIT_OOM_PROTECT 01697 if (strcmp(safe_argv[i], "--oom-pipe") == 0 && i+1<argc) 01698 oom_pipe = atol(argv[i+1]); 01699 #endif 01700 if (strcmp(safe_argv[i], "--help") == 0) 01701 { 01702 printf("Usage: kdeinit4 [options]\n"); 01703 // printf(" --no-dcop Do not start dcopserver\n"); 01704 #ifdef Q_WS_MACX 01705 printf(" --nofork Do not fork\n"); 01706 #else 01707 printf(" --no-fork Do not fork\n"); 01708 #endif 01709 // printf(" --no-klauncher Do not start klauncher\n"); 01710 printf(" --no-kded Do not start kded\n"); 01711 printf(" --suicide Terminate when no KDE applications are left running\n"); 01712 printf(" --version Show version information\n"); 01713 // printf(" --exit Terminate when kded has run\n"); 01714 exit(0); 01715 } 01716 } 01717 01718 cleanup_fds(); 01719 01720 // Redirect stdout to stderr. We have no reason to use stdout anyway. 01721 // This minimizes our impact on commands used in pipes. 01722 (void)dup2(2, 1); 01723 01724 if (do_fork) { 01725 #ifdef Q_WS_MACX 01726 mac_fork_and_reexec_self(); 01727 #else 01728 if (pipe(d.initpipe) != 0) { 01729 perror("kdeinit4: pipe failed"); 01730 return 1; 01731 } 01732 01733 // Fork here and let parent process exit. 01734 // Parent process may only exit after all required services have been 01735 // launched. (dcopserver/klauncher and services which start with '+') 01736 KDE_signal( SIGCHLD, secondary_child_handler); 01737 if (fork() > 0) // Go into background 01738 { 01739 close(d.initpipe[1]); 01740 d.initpipe[1] = -1; 01741 // wait till init is complete 01742 char c; 01743 while( read(d.initpipe[0], &c, 1) < 0) 01744 ; 01745 // then exit; 01746 close(d.initpipe[0]); 01747 d.initpipe[0] = -1; 01748 return 0; 01749 } 01750 close(d.initpipe[0]); 01751 d.initpipe[0] = -1; 01752 #endif 01753 } 01754 01756 if(keep_running) 01757 setsid(); 01758 01760 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration); 01761 01763 #ifndef SKIP_PROCTITLE 01764 proctitle_init(argc, argv, envp); 01765 #endif 01766 01767 kdeinit_library_path(); 01768 // Don't make our instance the global instance 01769 // (do it only after kdeinit_library_path, that one indirectly uses KConfig, 01770 // which seems to be buggy and always use KGlobal instead of the matching KComponentData) 01771 Q_ASSERT(!KGlobal::hasMainComponent()); 01772 // don't change envvars before proctitle_init() 01773 unsetenv("LD_BIND_NOW"); 01774 unsetenv("DYLD_BIND_AT_LAUNCH"); 01775 KApplication::loadedByKdeinit = true; 01776 01777 d.maxname = strlen(argv[0]); 01778 d.launcher_pid = 0; 01779 d.kded_pid = 0; 01780 d.wrapper = -1; 01781 d.accepted_fd = -1; 01782 d.debug_wait = false; 01783 d.launcher_ok = false; 01784 children = NULL; 01785 init_signals(); 01786 #ifdef Q_WS_X11 01787 setupX(); 01788 #endif 01789 01790 if (keep_running) 01791 { 01792 /* 01793 * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper 01794 * requests. 01795 */ 01796 init_kdeinit_socket(); 01797 } 01798 #ifdef Q_WS_X11 01799 if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty()) { 01800 const int extrasCount = sizeof(extra_libs)/sizeof(extra_libs[0]); 01801 for (int i=0; i<extrasCount; i++) { 01802 QString extra = KStandardDirs::locate("lib", QLatin1String(extra_libs[i]), *s_instance); 01803 01804 // can't use KLibLoader here as it would unload the library 01805 // again 01806 if (!extra.isEmpty()) { 01807 QLibrary l(extra); 01808 l.setLoadHints(QLibrary::ExportExternalSymbolsHint); 01809 l.load(); 01810 } 01811 #ifndef NDEBUG 01812 else { 01813 fprintf( stderr, "%s was not found.\n", extra_libs[i] ); 01814 } 01815 #endif 01816 01817 } 01818 } 01819 #endif 01820 if (launch_klauncher) 01821 { 01822 start_klauncher(); 01823 handle_requests(d.launcher_pid); // Wait for klauncher to be ready 01824 } 01825 01826 #ifdef Q_WS_X11 01827 X11fd = initXconnection(); 01828 #endif 01829 01830 { 01831 QFont::initialize(); 01832 #ifdef Q_WS_X11 01833 if (XSupportsLocale ()) 01834 { 01835 // Similar to QApplication::create_xim() 01836 // but we need to use our own display 01837 XOpenIM (X11display, 0, 0, 0); 01838 } 01839 #endif 01840 } 01841 01842 if (launch_kded) 01843 { 01844 setenv("KDED_STARTED_BY_KDEINIT", "1", true); 01845 pid = launch( 1, KDED_EXENAME, 0 ); 01846 unsetenv("KDED_STARTED_BY_KDEINIT"); 01847 #ifndef NDEBUG 01848 fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result); 01849 #endif 01850 d.kded_pid = pid; 01851 handle_requests(pid); 01852 } 01853 01854 for(int i = 1; i < argc; i++) 01855 { 01856 if (safe_argv[i][0] == '+') 01857 { 01858 pid = launch( 1, safe_argv[i]+1, 0); 01859 #ifndef NDEBUG 01860 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result); 01861 #endif 01862 handle_requests(pid); 01863 } 01864 else if (safe_argv[i][0] == '-' 01865 #ifdef KDEINIT_OOM_PROTECT 01866 || isdigit(safe_argv[i][0]) 01867 #endif 01868 ) 01869 { 01870 // Ignore 01871 } 01872 else 01873 { 01874 pid = launch( 1, safe_argv[i], 0 ); 01875 #ifndef NDEBUG 01876 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result); 01877 #endif 01878 } 01879 } 01880 01882 for(int i = 0; i < argc; i++) 01883 { 01884 free(safe_argv[i]); 01885 } 01886 free (safe_argv); 01887 01888 #ifndef SKIP_PROCTITLE 01889 proctitle_set("kdeinit4 Running..."); 01890 #endif 01891 01892 if (!keep_running) 01893 return 0; 01894 01895 if (d.initpipe[1] != -1) 01896 { 01897 char c = 0; 01898 write(d.initpipe[1], &c, 1); // Kdeinit is started. 01899 close(d.initpipe[1]); 01900 d.initpipe[1] = -1; 01901 } 01902 01903 handle_requests(0); 01904 01905 return 0; 01906 } 01907 01908
KDE 4.6 API Reference