00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define QT_NO_CAST_FROM_ASCII
00023
00024 #include <config.h>
00025
00026 #include <sys/types.h>
00027 #include <sys/time.h>
00028 #include <sys/resource.h>
00029 #include <sys/stat.h>
00030 #include <sys/socket.h>
00031 #include <sys/un.h>
00032 #include <sys/wait.h>
00033 #ifdef HAVE_SYS_SELECT_H
00034 #include <sys/select.h>
00035 #endif
00036
00037 #include <errno.h>
00038 #include <fcntl.h>
00039 #include "proctitle.h"
00040 #include <signal.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <unistd.h>
00045 #include <locale.h>
00046
00047 #include <QtCore/QLibrary>
00048 #include <QtCore/QString>
00049 #include <QtCore/QFile>
00050 #include <QtCore/QDate>
00051 #include <QtCore/QFileInfo>
00052 #include <QtCore/QRegExp>
00053 #include <QtGui/QFont>
00054 #include <kcomponentdata.h>
00055 #include <kdemacros.h>
00056 #include <kstandarddirs.h>
00057 #include <kglobalsettings.h>
00058 #include <kglobal.h>
00059 #include <kconfig.h>
00060 #include <klibloader.h>
00061 #include <kapplication.h>
00062 #include <klocale.h>
00063 #include <kdebug.h>
00064 #include <kde_file.h>
00065
00066 #ifdef Q_OS_LINUX
00067 #include <sys/prctl.h>
00068 #ifndef PR_SET_NAME
00069 #define PR_SET_NAME 15
00070 #endif
00071 #endif
00072
00073 #ifdef Q_WS_MACX
00074 #include <kkernel_mac.h>
00075 #endif
00076
00077 #include <kdeversion.h>
00078
00079 #include "klauncher_cmds.h"
00080
00081 #ifdef Q_WS_X11
00082 #include <X11/Xlib.h>
00083 #include <X11/Xatom.h>
00084 #include <fixx11h.h>
00085 #include <kstartupinfo.h>
00086 #endif
00087
00088 #if KDE_IS_VERSION( 3, 90, 0 )
00089 #ifdef __GNUC__
00090 #warning Check if Linux OOM-killer still sucks and if yes, forwardport revision 579164 and following fixes.
00091 #endif
00092 #endif
00093
00094
00095
00096 extern char **environ;
00097
00098 #ifdef Q_WS_X11
00099 static int X11fd = -1;
00100 static Display *X11display = 0;
00101 static int X11_startup_notify_fd = -1;
00102 static Display *X11_startup_notify_display = 0;
00103 #endif
00104 static KComponentData *s_instance = 0;
00105 #define MAX_SOCK_FILE 255
00106 static char sock_file[MAX_SOCK_FILE];
00107
00108 #ifdef Q_WS_X11
00109 #define DISPLAY "DISPLAY"
00110 #elif defined(Q_WS_QWS)
00111 #define DISPLAY "QWS_DISPLAY"
00112 #elif defined(Q_WS_MACX)
00113 #define DISPLAY "MAC_DISPLAY"
00114 #elif defined(Q_WS_WIN)
00115 #define DISPLAY "WIN_DISPLAY"
00116 #else
00117 #error Use QT/X11 or QT/Embedded
00118 #endif
00119
00120
00121 static struct {
00122 int maxname;
00123 int fd[2];
00124 int launcher[2];
00125 int deadpipe[2];
00126 int initpipe[2];
00127 int wrapper;
00128 int accepted_fd;
00129 char result;
00130 int exit_status;
00131 pid_t fork;
00132 pid_t launcher_pid;
00133 pid_t kded_pid;
00134 int n;
00135 char **argv;
00136 int (*func)(int, char *[]);
00137 int (*launcher_func)(int);
00138 bool debug_wait;
00139 QByteArray errorMsg;
00140 bool launcher_ok;
00141 bool suicide;
00142 } d;
00143
00144 struct child
00145 {
00146 pid_t pid;
00147 int sock;
00148 struct child *next;
00149 };
00150
00151 static struct child *children;
00152
00153 #ifdef Q_WS_X11
00154 extern "C" {
00155 int kdeinit_xio_errhandler( Display * );
00156 int kdeinit_x_errhandler( Display *, XErrorEvent *err );
00157 }
00158 #endif
00159
00160
00161 #include <kparts/plugin.h>
00162 extern "C" KParts::Plugin* _kinit_init_kparts() { return new KParts::Plugin(); }
00163
00164 #include <kio/authinfo.h>
00165 extern "C" KIO::AuthInfo* _kioslave_init_kio() { return new KIO::AuthInfo(); }
00166
00167
00168
00169
00170
00171
00172
00173
00174 static void cleanup_fds()
00175 {
00176 int maxfd = FD_SETSIZE;
00177 struct rlimit rl;
00178 if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
00179 maxfd = rl.rlim_max;
00180 for (int fd = 3; fd < maxfd; ++fd)
00181 close(fd);
00182 }
00183
00184
00185
00186
00187
00188 static void close_fds()
00189 {
00190 while (struct child *child = children) {
00191 close(child->sock);
00192 children = child->next;
00193 free(child);
00194 }
00195
00196 if (d.deadpipe[0] != -1)
00197 {
00198 close(d.deadpipe[0]);
00199 d.deadpipe[0] = -1;
00200 }
00201
00202 if (d.deadpipe[1] != -1)
00203 {
00204 close(d.deadpipe[1]);
00205 d.deadpipe[1] = -1;
00206 }
00207
00208 if (d.initpipe[0] != -1)
00209 {
00210 close(d.initpipe[0]);
00211 d.initpipe[0] = -1;
00212 }
00213
00214 if (d.initpipe[1] != -1)
00215 {
00216 close(d.initpipe[1]);
00217 d.initpipe[1] = -1;
00218 }
00219
00220 if (d.launcher[0] != -1)
00221 {
00222 close(d.launcher[0]);
00223 d.launcher[0] = -1;
00224 }
00225 if (d.wrapper != -1)
00226 {
00227 close(d.wrapper);
00228 d.wrapper = -1;
00229 }
00230 if (d.accepted_fd != -1)
00231 {
00232 close(d.accepted_fd);
00233 d.accepted_fd = -1;
00234 }
00235 #ifdef Q_WS_X11
00236 if (X11fd >= 0)
00237 {
00238 close(X11fd);
00239 X11fd = -1;
00240 }
00241 if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd )
00242 {
00243 close(X11_startup_notify_fd);
00244 X11_startup_notify_fd = -1;
00245 }
00246 #endif
00247
00248 KDE_signal(SIGCHLD, SIG_DFL);
00249 KDE_signal(SIGPIPE, SIG_DFL);
00250 }
00251
00252
00253 static void child_died(pid_t exit_pid, int exit_status)
00254 {
00255 struct child *child, **childptr = &children;
00256
00257 while ((child = *childptr))
00258 {
00259 if (child->pid == exit_pid)
00260 {
00261
00262 klauncher_header request_header;
00263 long request_data[2];
00264 request_header.cmd = LAUNCHER_CHILD_DIED;
00265 request_header.arg_length = sizeof(long) * 2;
00266 request_data[0] = exit_pid;
00267 request_data[1] = exit_status;
00268 write(child->sock, &request_header, sizeof(request_header));
00269 write(child->sock, request_data, request_header.arg_length);
00270 close(child->sock);
00271
00272 *childptr = child->next;
00273 free(child);
00274 return;
00275 }
00276
00277 childptr = &child->next;
00278 }
00279 }
00280
00281
00282 static void exitWithErrorMsg(const QString &errorMsg)
00283 {
00284 fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() );
00285 QByteArray utf8ErrorMsg = errorMsg.toUtf8();
00286 d.result = 3;
00287 write(d.fd[1], &d.result, 1);
00288 int l = utf8ErrorMsg.length();
00289 write(d.fd[1], &l, sizeof(int));
00290 write(d.fd[1], utf8ErrorMsg.data(), l);
00291 close(d.fd[1]);
00292 exit(255);
00293 }
00294
00295 static void setup_tty( const char* tty )
00296 {
00297 if( tty == NULL || *tty == '\0' )
00298 return;
00299 int fd = KDE_open( tty, O_WRONLY );
00300 if( fd < 0 )
00301 {
00302 perror( "kdeinit4: could not open() tty" );
00303 return;
00304 }
00305 if( dup2( fd, STDOUT_FILENO ) < 0 )
00306 {
00307 perror( "kdeinit4: could not dup2() stdout tty" );
00308 }
00309 if( dup2( fd, STDERR_FILENO ) < 0 )
00310 {
00311 perror( "kdeinit4: could not dup2() stderr tty" );
00312 }
00313 close( fd );
00314 }
00315
00316
00317 static int get_current_desktop( Display* disp )
00318 {
00319 int desktop = 0;
00320 #ifdef Q_WS_X11 // Only X11 supports multiple desktops
00321 Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False );
00322 Atom type_ret;
00323 int format_ret;
00324 unsigned char *data_ret;
00325 unsigned long nitems_ret, unused;
00326 if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop,
00327 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret )
00328 == Success)
00329 {
00330 if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1)
00331 desktop = *((long *) data_ret) + 1;
00332 if (data_ret)
00333 XFree ((char*) data_ret);
00334 }
00335 #endif
00336 return desktop;
00337 }
00338
00339
00340 const char* get_env_var( const char* var, int envc, const char* envs )
00341 {
00342 if( envc > 0 )
00343 {
00344 const char* env_l = envs;
00345 int ln = strlen( var );
00346 for (int i = 0; i < envc; i++)
00347 {
00348 if( strncmp( env_l, var, ln ) == 0 )
00349 return env_l + ln;
00350 while(*env_l != 0) env_l++;
00351 env_l++;
00352 }
00353 }
00354 return NULL;
00355 }
00356
00357 #ifdef Q_WS_X11
00358 static void init_startup_info( KStartupInfoId& id, const char* bin,
00359 int envc, const char* envs )
00360 {
00361 const char* dpy = get_env_var( DISPLAY"=", envc, envs );
00362
00363
00364 X11_startup_notify_display = XOpenDisplay( dpy );
00365 if( X11_startup_notify_display == NULL )
00366 return;
00367 X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display );
00368 KStartupInfoData data;
00369 int desktop = get_current_desktop( X11_startup_notify_display );
00370 data.setDesktop( desktop );
00371 data.setBin(QFile::decodeName(bin));
00372 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
00373 XFlush( X11_startup_notify_display );
00374 }
00375
00376 static void complete_startup_info( KStartupInfoId& id, pid_t pid )
00377 {
00378 if( X11_startup_notify_display == NULL )
00379 return;
00380 if( pid == 0 )
00381 KStartupInfo::sendFinishX( X11_startup_notify_display, id );
00382 else
00383 {
00384 KStartupInfoData data;
00385 data.addPid( pid );
00386 data.setHostname();
00387 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
00388 }
00389 XCloseDisplay( X11_startup_notify_display );
00390 X11_startup_notify_display = NULL;
00391 X11_startup_notify_fd = -1;
00392 }
00393 #endif
00394
00395 QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops )
00396 {
00397 QStringList paths;
00398 const QRegExp pathSepRegExp(QString::fromLatin1("[:\b]"));
00399 if( envc > 0 )
00400 {
00401 const char* path = get_env_var( "PATH=", envc, envs );
00402 if( path != NULL )
00403 paths = QFile::decodeName(path).split(pathSepRegExp);
00404 } else {
00405 paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSepRegExp, QString::KeepEmptyParts);
00406 }
00407 QString execpath =
00408 s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":")));
00409 if (avoid_loops && !execpath.isEmpty()) {
00410 const int pos = execpath.lastIndexOf(QLatin1Char('/'));
00411 const QString bin_path = execpath.left(pos);
00412 for( QStringList::Iterator it = paths.begin();
00413 it != paths.end();
00414 ++it ) {
00415 if( *it == bin_path || *it == bin_path + QLatin1Char('/')) {
00416 paths.erase( it );
00417 break;
00418 }
00419 }
00420 execpath = s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":")));
00421 }
00422 return QFile::encodeName(execpath);
00423 }
00424
00425 static pid_t launch(int argc, const char *_name, const char *args,
00426 const char *cwd=0, int envc=0, const char *envs=0,
00427 bool reset_env = false,
00428 const char *tty=0, bool avoid_loops = false,
00429 const char* startup_id_str = "0" )
00430 {
00431 QString lib;
00432 QByteArray name;
00433 QByteArray exec;
00434
00435 QString libpath;
00436 QByteArray execpath;
00437 if (_name[0] != '/') {
00438 name = _name;
00439 lib = QFile::decodeName(name);
00440 exec = name;
00441 libpath = KLibLoader::findLibrary( QLatin1String("libkdeinit4_") + lib, *s_instance);
00442 if( libpath.isEmpty())
00443 libpath = KLibLoader::findLibrary(lib, *s_instance);
00444 execpath = execpath_avoid_loops(exec, envc, envs, avoid_loops);
00445 } else {
00446 name = _name;
00447 lib = QFile::decodeName(name);
00448 name = name.mid(name.lastIndexOf('/') + 1);
00449 exec = _name;
00450 if (lib.endsWith(QLatin1String(".so")))
00451 libpath = lib;
00452 else {
00453
00454
00455 if( lib.contains( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ))) {
00456 libpath = QString( lib ).replace( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ),
00457 QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so");
00458 } else if( lib.contains( QLatin1String( "/bin/" ))) {
00459 libpath = QString( lib ).replace( QLatin1String( "/bin/" ),
00460 QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so");
00461 }
00462
00463 if (!QFile::exists(libpath)) {
00464 libpath = QString();
00465 }
00466 execpath = exec;
00467 }
00468 }
00469 #ifndef NDEBUG
00470 fprintf(stderr,"kdeinit4: preparing to launch %s\n", libpath.isEmpty()
00471 ? execpath.constData() : libpath.toUtf8().constData());
00472 #endif
00473 if (!args) {
00474 argc = 1;
00475 }
00476
00477 if (0 > pipe(d.fd))
00478 {
00479 perror("kdeinit4: pipe() failed");
00480 d.result = 3;
00481 d.errorMsg = i18n("Unable to start new process.\n"
00482 "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();
00483 d.fork = 0;
00484 return d.fork;
00485 }
00486
00487 #ifdef Q_WS_X11
00488 KStartupInfoId startup_id;
00489 startup_id.initId( startup_id_str );
00490 if( !startup_id.none())
00491 init_startup_info( startup_id, name, envc, envs );
00492 #endif
00493
00494 d.errorMsg = 0;
00495 d.fork = fork();
00496 switch(d.fork) {
00497 case -1:
00498 perror("kdeinit4: fork() failed");
00499 d.result = 3;
00500 d.errorMsg = i18n("Unable to create new process.\n"
00501 "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();
00502 close(d.fd[0]);
00503 close(d.fd[1]);
00504 d.fork = 0;
00505 break;
00506 case 0:
00507 {
00509 close(d.fd[0]);
00510 close_fds();
00511
00512
00513
00514
00515 if (cwd && *cwd) {
00516 (void)chdir(cwd);
00517 } else {
00518 const QByteArray docPath = QFile::encodeName(KGlobalSettings::documentPath());
00519 (void)chdir(docPath.constData());
00520 }
00521
00522 if( reset_env )
00523 {
00524
00525 QList<QByteArray> unset_envs;
00526 for( int tmp_env_count = 0;
00527 environ[tmp_env_count];
00528 tmp_env_count++)
00529 unset_envs.append( environ[ tmp_env_count ] );
00530 foreach(const QByteArray &tmp, unset_envs)
00531 {
00532 int pos = tmp.indexOf( '=' );
00533 if( pos >= 0 )
00534 unsetenv( tmp.left( pos ));
00535 }
00536 }
00537
00538 for (int i = 0; i < envc; i++)
00539 {
00540 putenv((char *)envs);
00541 while(*envs != 0) envs++;
00542 envs++;
00543 }
00544
00545 #ifdef Q_WS_X11
00546 if( startup_id.none())
00547 KStartupInfo::resetStartupEnv();
00548 else
00549 startup_id.setupStartupEnv();
00550 #endif
00551 {
00552 int r;
00553 QByteArray procTitle;
00554 d.argv = (char **) malloc(sizeof(char *) * (argc+1));
00555 d.argv[0] = (char *) _name;
00556 #ifdef Q_WS_MAC
00557 QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0]));
00558 if (!argvexe.isEmpty()) {
00559 QByteArray cstr = argvexe.toLocal8Bit();
00560 kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data();
00561 d.argv[0] = strdup(cstr.data());
00562 }
00563 #endif
00564 for (int i = 1; i < argc; i++)
00565 {
00566 d.argv[i] = (char *) args;
00567 procTitle += ' ';
00568 procTitle += (char *) args;
00569 while(*args != 0) args++;
00570 args++;
00571 }
00572 d.argv[argc] = 0;
00573
00574 #ifndef SKIP_PROCTITLE
00575
00576 #ifdef Q_OS_LINUX
00577
00578 r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0);
00579 if ( r == 0 )
00580 proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00581 else
00582 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00583 #else
00584 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00585 #endif
00586 #endif
00587 }
00588
00589 if (libpath.isEmpty() && execpath.isEmpty())
00590 {
00591 QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name));
00592 exitWithErrorMsg(errorMsg);
00593 }
00594
00595
00596 if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty())
00597 libpath.truncate(0);
00598
00599 QLibrary l(libpath);
00600
00601 if ( !libpath.isEmpty() )
00602 {
00603 if (!l.load() || !l.isLoaded() )
00604 {
00605 QString ltdlError (l.errorString());
00606 if (execpath.isEmpty())
00607 {
00608
00609 QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError);
00610 exitWithErrorMsg(errorMsg);
00611 }
00612 else
00613 {
00614
00615 fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib),
00616 qPrintable(ltdlError) );
00617 }
00618 }
00619 }
00620 if (!l.isLoaded())
00621 {
00622 d.result = 2;
00623 write(d.fd[1], &d.result, 1);
00624
00625
00626
00627 fcntl(d.fd[1], F_SETFD, FD_CLOEXEC);
00628
00629 setup_tty( tty );
00630
00631 QByteArray executable = execpath;
00632 #ifdef Q_WS_MAC
00633 QString bundlepath = s_instance->dirs()->findExe(QFile::decodeName(executable));
00634 if (!bundlepath.isEmpty())
00635 executable = QFile::encodeName(bundlepath);
00636 #endif
00637
00638 if (!executable.isEmpty())
00639 execvp(executable, d.argv);
00640
00641 d.result = 1;
00642 write(d.fd[1], &d.result, 1);
00643 close(d.fd[1]);
00644 exit(255);
00645 }
00646
00647 void * sym = l.resolve( "kdeinitmain");
00648 if (!sym )
00649 {
00650 sym = l.resolve( "kdemain" );
00651 if ( !sym )
00652 {
00653 QString ltdlError = l.errorString();
00654 fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) );
00655 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2",
00656 libpath, ltdlError);
00657 exitWithErrorMsg(errorMsg);
00658 }
00659 }
00660
00661 d.result = 0;
00662 write(d.fd[1], &d.result, 1);
00663 close(d.fd[1]);
00664
00665 d.func = (int (*)(int, char *[])) sym;
00666 if (d.debug_wait)
00667 {
00668 fprintf(stderr, "kdeinit4: Suspending process\n"
00669 "kdeinit4: 'gdb kdeinit4 %d' to debug\n"
00670 "kdeinit4: 'kill -SIGCONT %d' to continue\n",
00671 getpid(), getpid());
00672 kill(getpid(), SIGSTOP);
00673 }
00674 else
00675 {
00676 setup_tty( tty );
00677 }
00678
00679 exit( d.func(argc, d.argv));
00680
00681 break;
00682 }
00683 default:
00685 close(d.fd[1]);
00686 bool exec = false;
00687 for(;;)
00688 {
00689 d.n = read(d.fd[0], &d.result, 1);
00690 if (d.n == 1)
00691 {
00692 if (d.result == 2)
00693 {
00694 #ifndef NDEBUG
00695
00696 #endif
00697 exec = true;
00698 continue;
00699 }
00700 if (d.result == 3)
00701 {
00702 int l = 0;
00703 d.n = read(d.fd[0], &l, sizeof(int));
00704 if (d.n == sizeof(int))
00705 {
00706 QByteArray tmp;
00707 tmp.resize(l+1);
00708 d.n = read(d.fd[0], tmp.data(), l);
00709 tmp[l] = 0;
00710 if (d.n == l)
00711 d.errorMsg = tmp;
00712 }
00713 }
00714
00715 break;
00716 }
00717 if (d.n == -1)
00718 {
00719 if (errno == ECHILD) {
00720 continue;
00721 }
00722 if (errno == EINTR || errno == EAGAIN) {
00723 continue;
00724 }
00725 }
00726 if (d.n == 0)
00727 {
00728 if (exec) {
00729 d.result = 0;
00730 } else {
00731 fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData());
00732 perror("kdeinit4: Pipe closed unexpectedly");
00733 d.result = 1;
00734 }
00735 break;
00736 }
00737 perror("kdeinit4: Error reading from pipe");
00738 d.result = 1;
00739 break;
00740 }
00741 close(d.fd[0]);
00742 }
00743 #ifdef Q_WS_X11
00744 if( !startup_id.none())
00745 {
00746 if( d.fork && d.result == 0 )
00747 complete_startup_info( startup_id, d.fork );
00748 else
00749 complete_startup_info( startup_id, 0 );
00750 }
00751 #endif
00752 return d.fork;
00753 }
00754
00755 extern "C" {
00756
00757 static void sig_child_handler(int)
00758 {
00759
00760
00761
00762
00763
00764
00765
00766
00767 char c = 0;
00768 write(d.deadpipe[1], &c, 1);
00769 }
00770
00771 }
00772
00773 static void init_signals()
00774 {
00775 struct sigaction act;
00776 long options;
00777
00778 if (pipe(d.deadpipe) != 0)
00779 {
00780 perror("kdeinit4: Aborting. Can not create pipe");
00781 exit(255);
00782 }
00783
00784 options = fcntl(d.deadpipe[0], F_GETFL);
00785 if (options == -1)
00786 {
00787 perror("kdeinit4: Aborting. Can not make pipe non-blocking");
00788 exit(255);
00789 }
00790
00791 if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1)
00792 {
00793 perror("kdeinit4: Aborting. Can not make pipe non-blocking");
00794 exit(255);
00795 }
00796
00797
00798
00799
00800
00801
00802 act.sa_handler=sig_child_handler;
00803 sigemptyset(&(act.sa_mask));
00804 sigaddset(&(act.sa_mask), SIGCHLD);
00805 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00806 act.sa_flags = SA_NOCLDSTOP;
00807
00808
00809
00810
00811 #ifdef SA_RESTART
00812 act.sa_flags |= SA_RESTART;
00813 #endif
00814 sigaction( SIGCHLD, &act, 0L);
00815
00816 act.sa_handler=SIG_IGN;
00817 sigemptyset(&(act.sa_mask));
00818 sigaddset(&(act.sa_mask), SIGPIPE);
00819 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00820 act.sa_flags = 0;
00821 sigaction( SIGPIPE, &act, 0L);
00822 }
00823
00824 static void init_kdeinit_socket()
00825 {
00826 struct sockaddr_un sa;
00827 kde_socklen_t socklen;
00828 long options;
00829 const QByteArray home_dir = qgetenv("HOME");
00830 int max_tries = 10;
00831 if (home_dir.isEmpty())
00832 {
00833 fprintf(stderr, "kdeinit4: Aborting. $HOME not set!");
00834 exit(255);
00835 }
00836 if (chdir(home_dir) != 0) {
00837 fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData());
00838 exit(255);
00839 }
00840
00841 {
00842 QByteArray path = home_dir;
00843 QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00844 if (access(path.data(), R_OK|W_OK))
00845 {
00846 if (errno == ENOENT)
00847 {
00848 fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data());
00849 exit(255);
00850 }
00851 else if (readOnly.isEmpty())
00852 {
00853 fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data());
00854 exit(255);
00855 }
00856 }
00857 #if 0 // obsolete in kde4. Should we check writing to another file instead?
00858 path = qgetenv("ICEAUTHORITY");
00859 if (path.isEmpty())
00860 {
00861 path = home_dir;
00862 path += "/.ICEauthority";
00863 }
00864 if (access(path.data(), R_OK|W_OK) && (errno != ENOENT))
00865 {
00866 fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data());
00867 exit(255);
00868 }
00869 #endif
00870 }
00871
00876 if (access(sock_file, W_OK) == 0)
00877 {
00878 int s;
00879 struct sockaddr_un server;
00880
00881
00882
00883
00884
00885 s = socket(PF_UNIX, SOCK_STREAM, 0);
00886 if (s < 0)
00887 {
00888 perror("socket() failed");
00889 exit(255);
00890 }
00891 server.sun_family = AF_UNIX;
00892 strcpy(server.sun_path, sock_file);
00893 socklen = sizeof(server);
00894
00895 if(connect(s, (struct sockaddr *)&server, socklen) == 0)
00896 {
00897 fprintf(stderr, "kdeinit4: Shutting down running client.\n");
00898 klauncher_header request_header;
00899 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT;
00900 request_header.arg_length = 0;
00901 write(s, &request_header, sizeof(request_header));
00902 sleep(1);
00903 }
00904 close(s);
00905 }
00906
00908 unlink(sock_file);
00909
00911 d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0);
00912 if (d.wrapper < 0)
00913 {
00914 perror("kdeinit4: Aborting. socket() failed");
00915 exit(255);
00916 }
00917
00918 options = fcntl(d.wrapper, F_GETFL);
00919 if (options == -1)
00920 {
00921 perror("kdeinit4: Aborting. Can not make socket non-blocking");
00922 close(d.wrapper);
00923 exit(255);
00924 }
00925
00926 if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1)
00927 {
00928 perror("kdeinit4: Aborting. Can not make socket non-blocking");
00929 close(d.wrapper);
00930 exit(255);
00931 }
00932
00933 while (1) {
00935 socklen = sizeof(sa);
00936 memset(&sa, 0, socklen);
00937 sa.sun_family = AF_UNIX;
00938 strcpy(sa.sun_path, sock_file);
00939 if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0)
00940 {
00941 if (max_tries == 0) {
00942 perror("kdeinit4: Aborting. bind() failed");
00943 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file);
00944 close(d.wrapper);
00945 exit(255);
00946 }
00947 max_tries--;
00948 } else
00949 break;
00950 }
00951
00953 if (chmod(sock_file, 0600) != 0)
00954 {
00955 perror("kdeinit4: Aborting. Can not set permissions on socket");
00956 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
00957 unlink(sock_file);
00958 close(d.wrapper);
00959 exit(255);
00960 }
00961
00962 if(listen(d.wrapper, SOMAXCONN) < 0)
00963 {
00964 perror("kdeinit4: Aborting. listen() failed");
00965 unlink(sock_file);
00966 close(d.wrapper);
00967 exit(255);
00968 }
00969 }
00970
00971
00972
00973
00974
00975 static int read_socket(int sock, char *buffer, int len)
00976 {
00977 ssize_t result;
00978 int bytes_left = len;
00979 while ( bytes_left > 0)
00980 {
00981 result = read(sock, buffer, bytes_left);
00982 if (result > 0)
00983 {
00984 buffer += result;
00985 bytes_left -= result;
00986 }
00987 else if (result == 0)
00988 return -1;
00989 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
00990 return -1;
00991 }
00992 return 0;
00993 }
00994
00995 static void start_klauncher()
00996 {
00997 if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) {
00998 perror("kdeinit4: socketpair() failed");
00999 exit(255);
01000 }
01001 char args[32];
01002 strcpy(args, "--fd=");
01003 sprintf(args + 5, "%d", d.launcher[1]);
01004 d.launcher_pid = launch( 2, "klauncher", args );
01005 close(d.launcher[1]);
01006 #ifndef NDEBUG
01007 fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n",
01008 (long) d.launcher_pid, d.result);
01009 #endif
01010 }
01011
01012 static void launcher_died()
01013 {
01014 if (!d.launcher_ok)
01015 {
01016
01017 fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
01018 ::exit(255);
01019 return;
01020 }
01021
01022
01023 #ifndef NDEBUG
01024 fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
01025 #endif
01026
01027 if (d.launcher_pid)
01028 {
01029 kill(d.launcher_pid, SIGKILL);
01030 sleep(1);
01031 }
01032
01033 d.launcher_ok = false;
01034 d.launcher_pid = 0;
01035 close(d.launcher[0]);
01036 d.launcher[0] = -1;
01037
01038 start_klauncher();
01039 }
01040
01041 static bool handle_launcher_request(int sock, const char *who)
01042 {
01043 (void)who;
01044
01045 klauncher_header request_header;
01046 char *request_data = 0L;
01047 int result = read_socket(sock, (char *) &request_header, sizeof(request_header));
01048 if (result != 0)
01049 {
01050 return false;
01051 }
01052
01053 if ( request_header.arg_length != 0 )
01054 {
01055 request_data = (char *) malloc(request_header.arg_length);
01056
01057 result = read_socket(sock, request_data, request_header.arg_length);
01058 if (result != 0)
01059 {
01060 free(request_data);
01061 return false;
01062 }
01063 }
01064
01065
01066 if (request_header.cmd == LAUNCHER_OK)
01067 {
01068 d.launcher_ok = true;
01069 }
01070 else if (request_header.arg_length &&
01071 ((request_header.cmd == LAUNCHER_EXEC) ||
01072 (request_header.cmd == LAUNCHER_EXT_EXEC) ||
01073 (request_header.cmd == LAUNCHER_SHELL ) ||
01074 (request_header.cmd == LAUNCHER_KWRAPPER) ||
01075 (request_header.cmd == LAUNCHER_EXEC_NEW)))
01076 {
01077 pid_t pid;
01078 klauncher_header response_header;
01079 long response_data;
01080 long l;
01081 memcpy( &l, request_data, sizeof( long ));
01082 int argc = l;
01083 const char *name = request_data + sizeof(long);
01084 const char *args = name + strlen(name) + 1;
01085 const char *cwd = 0;
01086 int envc = 0;
01087 const char *envs = 0;
01088 const char *tty = 0;
01089 int avoid_loops = 0;
01090 const char *startup_id_str = "0";
01091
01092 #ifndef NDEBUG
01093 fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n",
01094 commandToString(request_header.cmd),
01095 name, who);
01096 #endif
01097
01098 const char *arg_n = args;
01099 for(int i = 1; i < argc; i++)
01100 {
01101 arg_n = arg_n + strlen(arg_n) + 1;
01102 }
01103
01104 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER )
01105 {
01106
01107 cwd = arg_n; arg_n += strlen(cwd) + 1;
01108 }
01109 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01110 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01111 {
01112 memcpy( &l, arg_n, sizeof( long ));
01113 envc = l;
01114 arg_n += sizeof(long);
01115 envs = arg_n;
01116 for(int i = 0; i < envc; i++)
01117 {
01118 arg_n = arg_n + strlen(arg_n) + 1;
01119 }
01120 if( request_header.cmd == LAUNCHER_KWRAPPER )
01121 {
01122 tty = arg_n;
01123 arg_n += strlen( tty ) + 1;
01124 }
01125 }
01126
01127 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01128 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01129 {
01130 memcpy( &l, arg_n, sizeof( long ));
01131 avoid_loops = l;
01132 arg_n += sizeof( long );
01133 }
01134
01135 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01136 || request_header.cmd == LAUNCHER_EXT_EXEC )
01137 {
01138 startup_id_str = arg_n;
01139 arg_n += strlen( startup_id_str ) + 1;
01140 }
01141
01142 if ((request_header.arg_length > (arg_n - request_data)) &&
01143 (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ))
01144 {
01145
01146 cwd = arg_n; arg_n += strlen(cwd) + 1;
01147 }
01148
01149 if ((arg_n - request_data) != request_header.arg_length)
01150 {
01151 #ifndef NDEBUG
01152 fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n");
01153 #endif
01154 free(request_data);
01155 d.debug_wait = false;
01156 return true;
01157 }
01158
01159
01160 QByteArray olddisplay = qgetenv(DISPLAY);
01161 QByteArray kdedisplay = qgetenv("KDE_DISPLAY");
01162 bool reset_display = (! olddisplay.isEmpty() &&
01163 ! kdedisplay.isEmpty() &&
01164 olddisplay != kdedisplay);
01165
01166 if (reset_display)
01167 setenv(DISPLAY, kdedisplay, true);
01168
01169 pid = launch( argc, name, args, cwd, envc, envs,
01170 request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER,
01171 tty, avoid_loops, startup_id_str );
01172
01173 if (reset_display) {
01174 unsetenv("KDE_DISPLAY");
01175 setenv(DISPLAY, olddisplay, true);
01176 }
01177
01178 if (pid && (d.result == 0))
01179 {
01180 response_header.cmd = LAUNCHER_OK;
01181 response_header.arg_length = sizeof(response_data);
01182 response_data = pid;
01183 write(sock, &response_header, sizeof(response_header));
01184 write(sock, &response_data, response_header.arg_length);
01185
01186
01187 struct child *child = (struct child *) malloc(sizeof(struct child));
01188 child->pid = pid;
01189 child->sock = dup(sock);
01190 child->next = children;
01191 children = child;
01192 }
01193 else
01194 {
01195 int l = d.errorMsg.length();
01196 if (l) l++;
01197 response_header.cmd = LAUNCHER_ERROR;
01198 response_header.arg_length = l;
01199 write(sock, &response_header, sizeof(response_header));
01200 if (l)
01201 write(sock, d.errorMsg.data(), l);
01202 }
01203 d.debug_wait = false;
01204 }
01205 else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV)
01206 {
01207 const char *env_name;
01208 const char *env_value;
01209 env_name = request_data;
01210 env_value = env_name + strlen(env_name) + 1;
01211
01212 #ifndef NDEBUG
01213 fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who);
01214 #endif
01215
01216 if ( request_header.arg_length !=
01217 (int) (strlen(env_name) + strlen(env_value) + 2))
01218 {
01219 #ifndef NDEBUG
01220 fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n");
01221 #endif
01222 free(request_data);
01223 return true;
01224 }
01225 setenv( env_name, env_value, 1);
01226 }
01227 else if (request_header.cmd == LAUNCHER_TERMINATE_KDE)
01228 {
01229 #ifndef NDEBUG
01230 fprintf(stderr,"kdeinit4: terminate KDE.\n");
01231 #endif
01232 #ifdef Q_WS_X11
01233 kdeinit_xio_errhandler( 0L );
01234 #endif
01235 }
01236 else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT)
01237 {
01238 #ifndef NDEBUG
01239 fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid());
01240 #endif
01241 if (d.launcher_pid) {
01242 kill(d.launcher_pid, SIGTERM);
01243 d.launcher_pid = 0;
01244 close(d.launcher[0]);
01245 d.launcher[0] = -1;
01246 }
01247 unlink(sock_file);
01248 if (children) {
01249 close(d.wrapper);
01250 d.wrapper = -1;
01251 #ifndef NDEBUG
01252 fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n");
01253 #endif
01254 } else {
01255 raise(SIGTERM);
01256 }
01257 }
01258 else if (request_header.cmd == LAUNCHER_DEBUG_WAIT)
01259 {
01260 #ifndef NDEBUG
01261 fprintf(stderr,"kdeinit4: Debug wait activated.\n");
01262 #endif
01263 d.debug_wait = true;
01264 }
01265 if (request_data)
01266 free(request_data);
01267 return true;
01268 }
01269
01270 static void handle_requests(pid_t waitForPid)
01271 {
01272 int max_sock = d.deadpipe[0];
01273 if (d.wrapper > max_sock)
01274 max_sock = d.wrapper;
01275 if (d.launcher[0] > max_sock)
01276 max_sock = d.launcher[0];
01277 #ifdef Q_WS_X11
01278 if (X11fd > max_sock)
01279 max_sock = X11fd;
01280 #endif
01281 max_sock++;
01282
01283 while(1)
01284 {
01285 fd_set rd_set;
01286 fd_set wr_set;
01287 fd_set e_set;
01288 int result;
01289 pid_t exit_pid;
01290 int exit_status;
01291 char c;
01292
01293
01294 while( read(d.deadpipe[0], &c, 1) == 1)
01295 {}
01296
01297
01298 do {
01299 exit_pid = waitpid(-1, &exit_status, WNOHANG);
01300 if (exit_pid > 0)
01301 {
01302 #ifndef NDEBUG
01303 fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid);
01304 #endif
01305 if (waitForPid && (exit_pid == waitForPid))
01306 return;
01307
01308 if( WIFEXITED( exit_status ))
01309 exit_status = WEXITSTATUS(exit_status);
01310 else if( WIFSIGNALED( exit_status ))
01311 exit_status = 128 + WTERMSIG( exit_status );
01312 child_died(exit_pid, exit_status);
01313
01314 if (d.wrapper < 0 && !children) {
01315 #ifndef NDEBUG
01316 fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n",
01317 (long) getpid());
01318 #endif
01319 raise(SIGTERM);
01320 }
01321 }
01322 }
01323 while( exit_pid > 0);
01324
01325 FD_ZERO(&rd_set);
01326 FD_ZERO(&wr_set);
01327 FD_ZERO(&e_set);
01328
01329 if (d.launcher[0] >= 0)
01330 FD_SET(d.launcher[0], &rd_set);
01331 if (d.wrapper >= 0)
01332 FD_SET(d.wrapper, &rd_set);
01333 FD_SET(d.deadpipe[0], &rd_set);
01334 #ifdef Q_WS_X11
01335 if(X11fd >= 0) FD_SET(X11fd, &rd_set);
01336 #endif
01337
01338 result = select(max_sock, &rd_set, &wr_set, &e_set, 0);
01339 if (result < 0) {
01340 if (errno == EINTR || errno == EAGAIN)
01341 continue;
01342 perror("kdeinit4: Aborting. select() failed");
01343 return;
01344 }
01345
01346
01347 if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set))
01348 {
01349 struct sockaddr_un client;
01350 kde_socklen_t sClient = sizeof(client);
01351 int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient);
01352 if (sock >= 0)
01353 {
01354 d.accepted_fd = sock;
01355 handle_launcher_request(sock, "wrapper");
01356 close(sock);
01357 d.accepted_fd = -1;
01358 }
01359 }
01360
01361
01362 if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set))
01363 {
01364 if (!handle_launcher_request(d.launcher[0], "launcher"))
01365 launcher_died();
01366 if (waitForPid == d.launcher_pid)
01367 return;
01368 }
01369
01370 #ifdef Q_WS_X11
01371
01372 if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) {
01373 if (X11display != 0) {
01374 XEvent event_return;
01375 while (XPending(X11display))
01376 XNextEvent(X11display, &event_return);
01377 }
01378 }
01379 #endif
01380 }
01381 }
01382
01383 static void kdeinit_library_path()
01384 {
01385 const QStringList ltdl_library_path =
01386 QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(QLatin1Char(':'),QString::SkipEmptyParts);
01387 #ifdef Q_OS_DARWIN
01388 const QByteArray ldlibpath = qgetenv("DYLD_LIBRARY_PATH");
01389 #else
01390 const QByteArray ldlibpath = qgetenv("LD_LIBRARY_PATH");
01391 #endif
01392 const QStringList ld_library_path =
01393 QFile::decodeName(ldlibpath).split(QLatin1Char(':'),QString::SkipEmptyParts);
01394
01395 QByteArray extra_path;
01396 const QStringList candidates = s_instance->dirs()->resourceDirs("lib");
01397 for (QStringList::ConstIterator it = candidates.begin();
01398 it != candidates.end();
01399 ++it)
01400 {
01401 QString d = *it;
01402 if (ltdl_library_path.contains(d))
01403 continue;
01404 if (ld_library_path.contains(d))
01405 continue;
01406 if (d[d.length()-1] == QLatin1Char('/'))
01407 {
01408 d.truncate(d.length()-1);
01409 if (ltdl_library_path.contains(d))
01410 continue;
01411 if (ld_library_path.contains(d))
01412 continue;
01413 }
01414 if ((d == QLatin1String("/lib")) || (d == QLatin1String("/usr/lib")))
01415 continue;
01416
01417 QByteArray dir = QFile::encodeName(d);
01418
01419 if (access(dir, R_OK))
01420 continue;
01421
01422 if ( !extra_path.isEmpty())
01423 extra_path += ':';
01424 extra_path += dir;
01425 }
01426
01427
01428
01429
01430 QByteArray display = qgetenv(DISPLAY);
01431 if (display.isEmpty())
01432 {
01433 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
01434 fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n");
01435 exit(255);
01436 #endif
01437 }
01438 int i;
01439 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
01440 display.truncate(i);
01441
01442 display.replace(':','_');
01443 #ifdef __APPLE__
01444 display.replace('/','_');
01445 #endif
01446
01447 const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display));
01448 QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", socketFileName, *s_instance));
01449 if (socketName.length() >= MAX_SOCK_FILE)
01450 {
01451 fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
01452 fprintf(stderr, " '%s'\n", socketName.data());
01453 exit(255);
01454 }
01455 strcpy(sock_file, socketName.data());
01456 }
01457
01458 int kdeinit_xio_errhandler( Display *disp )
01459 {
01460
01461
01462 if ( disp )
01463 qWarning( "kdeinit4: Fatal IO error: client killed" );
01464
01465 if (sock_file[0])
01466 {
01468 unlink(sock_file);
01469 }
01470
01471
01472 if (d.suicide)
01473 {
01474 if (d.launcher_pid)
01475 kill(d.launcher_pid, SIGTERM);
01476 if (d.kded_pid)
01477 kill(d.kded_pid, SIGTERM);
01478 exit( 0 );
01479 }
01480
01481 if ( disp )
01482 qWarning( "kdeinit4: sending SIGHUP to children." );
01483
01484
01485 KDE_signal(SIGHUP, SIG_IGN);
01486 kill(0, SIGHUP);
01487
01488 sleep(2);
01489
01490 if ( disp )
01491 qWarning( "kdeinit4: sending SIGTERM to children." );
01492
01493
01494 KDE_signal(SIGTERM, SIG_IGN);
01495 kill(0, SIGTERM);
01496
01497 if ( disp )
01498 qWarning( "kdeinit4: Exit." );
01499
01500 exit( 0 );
01501 return 0;
01502 }
01503
01504 #ifdef Q_WS_X11
01505 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err )
01506 {
01507 #ifndef NDEBUG
01508 char errstr[256];
01509
01510 XGetErrorText( dpy, err->error_code, errstr, 256 );
01511 fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n"
01512 " Major opcode: %d\n"
01513 " Minor opcode: %d\n"
01514 " Resource id: 0x%lx\n",
01515 getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid );
01516
01517
01518
01519 #else
01520 Q_UNUSED(dpy);
01521 Q_UNUSED(err);
01522 #endif
01523 return 0;
01524 }
01525 #endif
01526
01527 #ifdef Q_WS_X11
01528
01529
01530 static void setupX()
01531 {
01532 XSetIOErrorHandler(kdeinit_xio_errhandler);
01533 XSetErrorHandler(kdeinit_x_errhandler);
01534 }
01535
01536
01537 static int initXconnection()
01538 {
01539 X11display = XOpenDisplay(NULL);
01540 if ( X11display != 0 ) {
01541 XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \
01542 0,
01543 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)),
01544 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) );
01545 #ifndef NDEBUG
01546 fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display));
01547 #endif
01548 int fd = XConnectionNumber( X11display );
01549 int on = 1;
01550 (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on));
01551 return fd;
01552 } else
01553 fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \
01554 "kdeinit4: Might not terminate at end of session.\n");
01555
01556 return -1;
01557 }
01558 #endif
01559
01560 extern "C" {
01561
01562 static void secondary_child_handler(int)
01563 {
01564 waitpid(-1, 0, WNOHANG);
01565 }
01566
01567 }
01568
01569 int main(int argc, char **argv, char **envp)
01570 {
01571 setlocale (LC_ALL, "");
01572 setlocale (LC_NUMERIC, "C");
01573
01574 pid_t pid;
01575 bool do_fork = true;
01576 int launch_klauncher = 1;
01577 int launch_kded = 1;
01578 int keep_running = 1;
01579 d.suicide = false;
01580
01582 char **safe_argv = (char **) malloc( sizeof(char *) * argc);
01583 for(int i = 0; i < argc; i++)
01584 {
01585 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
01586 if (strcmp(safe_argv[i], "--no-klauncher") == 0)
01587 launch_klauncher = 0;
01588 if (strcmp(safe_argv[i], "--no-kded") == 0)
01589 launch_kded = 0;
01590 #ifdef Q_WS_MACX
01591
01592 if (strcmp(safe_argv[i], "--nofork") == 0)
01593 #else
01594 if (strcmp(safe_argv[i], "--no-fork") == 0)
01595 #endif
01596 do_fork = false;
01597 if (strcmp(safe_argv[i], "--suicide") == 0)
01598 d.suicide = true;
01599 if (strcmp(safe_argv[i], "--exit") == 0)
01600 keep_running = 0;
01601 if (strcmp(safe_argv[i], "--version") == 0)
01602 {
01603 printf("Qt: %s\n", qVersion());
01604 printf("KDE: %s\n", KDE_VERSION_STRING);
01605 exit(0);
01606 }
01607 if (strcmp(safe_argv[i], "--help") == 0)
01608 {
01609 printf("Usage: kdeinit4 [options]\n");
01610
01611 #ifdef Q_WS_MACX
01612 printf(" --nofork Do not fork\n");
01613 #else
01614 printf(" --no-fork Do not fork\n");
01615 #endif
01616
01617 printf(" --no-kded Do not start kded\n");
01618 printf(" --suicide Terminate when no KDE applications are left running\n");
01619 printf(" --version Show version information\n");
01620
01621 exit(0);
01622 }
01623 }
01624
01625 cleanup_fds();
01626
01627 if (do_fork) {
01628 #ifdef Q_WS_MACX
01629 mac_fork_and_reexec_self();
01630 #else
01631 if (pipe(d.initpipe) != 0) {
01632 perror("kdeinit4: pipe failed");
01633 return 1;
01634 }
01635
01636
01637
01638
01639 KDE_signal( SIGCHLD, secondary_child_handler);
01640 if (fork() > 0)
01641 {
01642 close(d.initpipe[1]);
01643 d.initpipe[1] = -1;
01644
01645 char c;
01646 while( read(d.initpipe[0], &c, 1) < 0)
01647 ;
01648
01649 close(d.initpipe[0]);
01650 d.initpipe[0] = -1;
01651 return 0;
01652 }
01653 close(d.initpipe[0]);
01654 d.initpipe[0] = -1;
01655 #endif
01656 }
01657
01659 if(keep_running)
01660 setsid();
01661
01663 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
01664
01666 #ifndef SKIP_PROCTITLE
01667 proctitle_init(argc, argv, envp);
01668 #endif
01669
01670 kdeinit_library_path();
01671
01672
01673
01674 Q_ASSERT(!KGlobal::hasMainComponent());
01675
01676 unsetenv("LD_BIND_NOW");
01677 unsetenv("DYLD_BIND_AT_LAUNCH");
01678 KApplication::loadedByKdeinit = true;
01679
01680 d.maxname = strlen(argv[0]);
01681 d.launcher_pid = 0;
01682 d.kded_pid = 0;
01683 d.wrapper = -1;
01684 d.accepted_fd = -1;
01685 d.debug_wait = false;
01686 d.launcher_ok = false;
01687 children = NULL;
01688 init_signals();
01689 #ifdef Q_WS_X11
01690 setupX();
01691 #endif
01692
01693 if (keep_running)
01694 {
01695
01696
01697
01698
01699 init_kdeinit_socket();
01700 }
01701 #ifdef Q_WS_X11
01702 if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty())
01703 {
01704 #ifdef __KDE_HAVE_GCC_VISIBILITY
01705 QString extra = KStandardDirs::locate("lib", QLatin1String("libplasma.so.3"), *s_instance);
01706 #else
01707 QString extra;
01708 #endif
01709
01710
01711 if (!extra.isEmpty()) {
01712 QLibrary l(extra);
01713 l.setLoadHints(QLibrary::ExportExternalSymbolsHint);
01714 l.load();
01715 }
01716 }
01717 #endif
01718 if (launch_klauncher)
01719 {
01720 start_klauncher();
01721 handle_requests(d.launcher_pid);
01722 }
01723
01724 #ifdef Q_WS_X11
01725 X11fd = initXconnection();
01726 #endif
01727
01728 {
01729 QFont::initialize();
01730 #ifdef Q_WS_X11
01731 if (XSupportsLocale ())
01732 {
01733
01734
01735 XOpenIM (X11display, 0, 0, 0);
01736 }
01737 #endif
01738 }
01739
01740 if (launch_kded)
01741 {
01742 pid = launch( 1, KDED_EXENAME, 0 );
01743 #ifndef NDEBUG
01744 fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result);
01745 #endif
01746 d.kded_pid = pid;
01747 handle_requests(pid);
01748 }
01749
01750 for(int i = 1; i < argc; i++)
01751 {
01752 if (safe_argv[i][0] == '+')
01753 {
01754 pid = launch( 1, safe_argv[i]+1, 0);
01755 #ifndef NDEBUG
01756 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result);
01757 #endif
01758 handle_requests(pid);
01759 }
01760 else if (safe_argv[i][0] == '-')
01761 {
01762
01763 }
01764 else
01765 {
01766 pid = launch( 1, safe_argv[i], 0 );
01767 #ifndef NDEBUG
01768 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result);
01769 #endif
01770 }
01771 }
01772
01774 for(int i = 0; i < argc; i++)
01775 {
01776 free(safe_argv[i]);
01777 }
01778 free (safe_argv);
01779
01780 #ifndef SKIP_PROCTITLE
01781 proctitle_set("kdeinit4 Running...");
01782 #endif
01783
01784 if (!keep_running)
01785 return 0;
01786
01787 if (d.initpipe[1] != -1)
01788 {
01789 char c = 0;
01790 write(d.initpipe[1], &c, 1);
01791 close(d.initpipe[1]);
01792 d.initpipe[1] = -1;
01793 }
01794
01795 handle_requests(0);
01796
01797 return 0;
01798 }
01799
01800