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 fprintf(stderr,"kdeinit4: preparing to launch %s\n", libpath.isEmpty()
00470 ? execpath.constData() : libpath.toUtf8().constData());
00471 if (!args) {
00472 argc = 1;
00473 }
00474
00475 if (0 > pipe(d.fd))
00476 {
00477 perror("kdeinit4: pipe() failed");
00478 d.result = 3;
00479 d.errorMsg = i18n("Unable to start new process.\n"
00480 "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();
00481 d.fork = 0;
00482 return d.fork;
00483 }
00484
00485 #ifdef Q_WS_X11
00486 KStartupInfoId startup_id;
00487 startup_id.initId( startup_id_str );
00488 if( !startup_id.none())
00489 init_startup_info( startup_id, name, envc, envs );
00490 #endif
00491
00492 d.errorMsg = 0;
00493 d.fork = fork();
00494 switch(d.fork) {
00495 case -1:
00496 perror("kdeinit4: fork() failed");
00497 d.result = 3;
00498 d.errorMsg = i18n("Unable to create new process.\n"
00499 "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();
00500 close(d.fd[0]);
00501 close(d.fd[1]);
00502 d.fork = 0;
00503 break;
00504 case 0:
00505 {
00507 close(d.fd[0]);
00508 close_fds();
00509
00510
00511
00512
00513 if (cwd && *cwd) {
00514 (void)chdir(cwd);
00515 } else {
00516 const QByteArray docPath = QFile::encodeName(KGlobalSettings::documentPath());
00517 (void)chdir(docPath.constData());
00518 }
00519
00520 if( reset_env )
00521 {
00522
00523 QList<QByteArray> unset_envs;
00524 for( int tmp_env_count = 0;
00525 environ[tmp_env_count];
00526 tmp_env_count++)
00527 unset_envs.append( environ[ tmp_env_count ] );
00528 foreach(const QByteArray &tmp, unset_envs)
00529 {
00530 int pos = tmp.indexOf( '=' );
00531 if( pos >= 0 )
00532 unsetenv( tmp.left( pos ));
00533 }
00534 }
00535
00536 for (int i = 0; i < envc; i++)
00537 {
00538 putenv((char *)envs);
00539 while(*envs != 0) envs++;
00540 envs++;
00541 }
00542
00543 #ifdef Q_WS_X11
00544 if( startup_id.none())
00545 KStartupInfo::resetStartupEnv();
00546 else
00547 startup_id.setupStartupEnv();
00548 #endif
00549 {
00550 int r;
00551 QByteArray procTitle;
00552 d.argv = (char **) malloc(sizeof(char *) * (argc+1));
00553 d.argv[0] = (char *) _name;
00554 #ifdef Q_WS_MAC
00555 QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0]));
00556 if (!argvexe.isEmpty()) {
00557 QByteArray cstr = argvexe.toLocal8Bit();
00558 kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data();
00559 d.argv[0] = strdup(cstr.data());
00560 }
00561 #endif
00562 for (int i = 1; i < argc; i++)
00563 {
00564 d.argv[i] = (char *) args;
00565 procTitle += ' ';
00566 procTitle += (char *) args;
00567 while(*args != 0) args++;
00568 args++;
00569 }
00570 d.argv[argc] = 0;
00571
00572 #ifndef SKIP_PROCTITLE
00573
00574 #ifdef Q_OS_LINUX
00575
00576 r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0);
00577 if ( r == 0 )
00578 proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00579 else
00580 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00581 #else
00582 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00583 #endif
00584 #endif
00585 }
00586
00587 if (libpath.isEmpty() && execpath.isEmpty())
00588 {
00589 QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name));
00590 exitWithErrorMsg(errorMsg);
00591 }
00592
00593
00594 if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty())
00595 libpath.truncate(0);
00596
00597 QLibrary l(libpath);
00598
00599 if ( !libpath.isEmpty() )
00600 {
00601 if (!l.load() || !l.isLoaded() )
00602 {
00603 QString ltdlError (l.errorString());
00604 if (execpath.isEmpty())
00605 {
00606
00607 QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError);
00608 exitWithErrorMsg(errorMsg);
00609 }
00610 else
00611 {
00612
00613 fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib),
00614 qPrintable(ltdlError) );
00615 }
00616 }
00617 }
00618 if (!l.isLoaded())
00619 {
00620 d.result = 2;
00621 write(d.fd[1], &d.result, 1);
00622
00623
00624
00625 fcntl(d.fd[1], F_SETFD, FD_CLOEXEC);
00626
00627 setup_tty( tty );
00628
00629 QByteArray executable = execpath;
00630 #ifdef Q_WS_MAC
00631 QString bundlepath = s_instance->dirs()->findExe(QFile::decodeName(executable));
00632 if (!bundlepath.isEmpty())
00633 executable = QFile::encodeName(bundlepath);
00634 #endif
00635
00636 if (!executable.isEmpty())
00637 execvp(executable, d.argv);
00638
00639 d.result = 1;
00640 write(d.fd[1], &d.result, 1);
00641 close(d.fd[1]);
00642 exit(255);
00643 }
00644
00645 void * sym = l.resolve( "kdeinitmain");
00646 if (!sym )
00647 {
00648 sym = l.resolve( "kdemain" );
00649 if ( !sym )
00650 {
00651 QString ltdlError = l.errorString();
00652 fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) );
00653 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2",
00654 libpath, ltdlError);
00655 exitWithErrorMsg(errorMsg);
00656 }
00657 }
00658
00659 d.result = 0;
00660 write(d.fd[1], &d.result, 1);
00661 close(d.fd[1]);
00662
00663 d.func = (int (*)(int, char *[])) sym;
00664 if (d.debug_wait)
00665 {
00666 fprintf(stderr, "kdeinit4: Suspending process\n"
00667 "kdeinit4: 'gdb kdeinit4 %d' to debug\n"
00668 "kdeinit4: 'kill -SIGCONT %d' to continue\n",
00669 getpid(), getpid());
00670 kill(getpid(), SIGSTOP);
00671 }
00672 else
00673 {
00674 setup_tty( tty );
00675 }
00676
00677 exit( d.func(argc, d.argv));
00678
00679 break;
00680 }
00681 default:
00683 close(d.fd[1]);
00684 bool exec = false;
00685 for(;;)
00686 {
00687 d.n = read(d.fd[0], &d.result, 1);
00688 if (d.n == 1)
00689 {
00690 if (d.result == 2)
00691 {
00692 #ifndef NDEBUG
00693
00694 #endif
00695 exec = true;
00696 continue;
00697 }
00698 if (d.result == 3)
00699 {
00700 int l = 0;
00701 d.n = read(d.fd[0], &l, sizeof(int));
00702 if (d.n == sizeof(int))
00703 {
00704 QByteArray tmp;
00705 tmp.resize(l+1);
00706 d.n = read(d.fd[0], tmp.data(), l);
00707 tmp[l] = 0;
00708 if (d.n == l)
00709 d.errorMsg = tmp;
00710 }
00711 }
00712
00713 break;
00714 }
00715 if (d.n == -1)
00716 {
00717 if (errno == ECHILD) {
00718 continue;
00719 }
00720 if (errno == EINTR || errno == EAGAIN) {
00721 continue;
00722 }
00723 }
00724 if (d.n == 0)
00725 {
00726 if (exec) {
00727 d.result = 0;
00728 } else {
00729 fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData());
00730 perror("kdeinit4: Pipe closed unexpectedly");
00731 d.result = 1;
00732 }
00733 break;
00734 }
00735 perror("kdeinit4: Error reading from pipe");
00736 d.result = 1;
00737 break;
00738 }
00739 close(d.fd[0]);
00740 }
00741 #ifdef Q_WS_X11
00742 if( !startup_id.none())
00743 {
00744 if( d.fork && d.result == 0 )
00745 complete_startup_info( startup_id, d.fork );
00746 else
00747 complete_startup_info( startup_id, 0 );
00748 }
00749 #endif
00750 return d.fork;
00751 }
00752
00753 extern "C" {
00754
00755 static void sig_child_handler(int)
00756 {
00757
00758
00759
00760
00761
00762
00763
00764
00765 char c = 0;
00766 write(d.deadpipe[1], &c, 1);
00767 }
00768
00769 }
00770
00771 static void init_signals()
00772 {
00773 struct sigaction act;
00774 long options;
00775
00776 if (pipe(d.deadpipe) != 0)
00777 {
00778 perror("kdeinit4: Aborting. Can not create pipe");
00779 exit(255);
00780 }
00781
00782 options = fcntl(d.deadpipe[0], F_GETFL);
00783 if (options == -1)
00784 {
00785 perror("kdeinit4: Aborting. Can not make pipe non-blocking");
00786 exit(255);
00787 }
00788
00789 if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1)
00790 {
00791 perror("kdeinit4: Aborting. Can not make pipe non-blocking");
00792 exit(255);
00793 }
00794
00795
00796
00797
00798
00799
00800 act.sa_handler=sig_child_handler;
00801 sigemptyset(&(act.sa_mask));
00802 sigaddset(&(act.sa_mask), SIGCHLD);
00803 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00804 act.sa_flags = SA_NOCLDSTOP;
00805
00806
00807
00808
00809 #ifdef SA_RESTART
00810 act.sa_flags |= SA_RESTART;
00811 #endif
00812 sigaction( SIGCHLD, &act, 0L);
00813
00814 act.sa_handler=SIG_IGN;
00815 sigemptyset(&(act.sa_mask));
00816 sigaddset(&(act.sa_mask), SIGPIPE);
00817 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00818 act.sa_flags = 0;
00819 sigaction( SIGPIPE, &act, 0L);
00820 }
00821
00822 static void init_kdeinit_socket()
00823 {
00824 struct sockaddr_un sa;
00825 kde_socklen_t socklen;
00826 long options;
00827 const QByteArray home_dir = qgetenv("HOME");
00828 int max_tries = 10;
00829 if (home_dir.isEmpty())
00830 {
00831 fprintf(stderr, "kdeinit4: Aborting. $HOME not set!");
00832 exit(255);
00833 }
00834 if (chdir(home_dir) != 0) {
00835 fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData());
00836 exit(255);
00837 }
00838
00839 {
00840 QByteArray path = home_dir;
00841 QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00842 if (access(path.data(), R_OK|W_OK))
00843 {
00844 if (errno == ENOENT)
00845 {
00846 fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data());
00847 exit(255);
00848 }
00849 else if (readOnly.isEmpty())
00850 {
00851 fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data());
00852 exit(255);
00853 }
00854 }
00855 #if 0 // obsolete in kde4. Should we check writing to another file instead?
00856 path = qgetenv("ICEAUTHORITY");
00857 if (path.isEmpty())
00858 {
00859 path = home_dir;
00860 path += "/.ICEauthority";
00861 }
00862 if (access(path.data(), R_OK|W_OK) && (errno != ENOENT))
00863 {
00864 fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data());
00865 exit(255);
00866 }
00867 #endif
00868 }
00869
00874 if (access(sock_file, W_OK) == 0)
00875 {
00876 int s;
00877 struct sockaddr_un server;
00878
00879
00880
00881
00882
00883 s = socket(PF_UNIX, SOCK_STREAM, 0);
00884 if (s < 0)
00885 {
00886 perror("socket() failed");
00887 exit(255);
00888 }
00889 server.sun_family = AF_UNIX;
00890 strcpy(server.sun_path, sock_file);
00891 socklen = sizeof(server);
00892
00893 if(connect(s, (struct sockaddr *)&server, socklen) == 0)
00894 {
00895 fprintf(stderr, "kdeinit4: Shutting down running client.\n");
00896 klauncher_header request_header;
00897 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT;
00898 request_header.arg_length = 0;
00899 write(s, &request_header, sizeof(request_header));
00900 sleep(1);
00901 }
00902 close(s);
00903 }
00904
00906 unlink(sock_file);
00907
00909 d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0);
00910 if (d.wrapper < 0)
00911 {
00912 perror("kdeinit4: Aborting. socket() failed");
00913 exit(255);
00914 }
00915
00916 options = fcntl(d.wrapper, F_GETFL);
00917 if (options == -1)
00918 {
00919 perror("kdeinit4: Aborting. Can not make socket non-blocking");
00920 close(d.wrapper);
00921 exit(255);
00922 }
00923
00924 if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1)
00925 {
00926 perror("kdeinit4: Aborting. Can not make socket non-blocking");
00927 close(d.wrapper);
00928 exit(255);
00929 }
00930
00931 while (1) {
00933 socklen = sizeof(sa);
00934 memset(&sa, 0, socklen);
00935 sa.sun_family = AF_UNIX;
00936 strcpy(sa.sun_path, sock_file);
00937 if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0)
00938 {
00939 if (max_tries == 0) {
00940 perror("kdeinit4: Aborting. bind() failed");
00941 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file);
00942 close(d.wrapper);
00943 exit(255);
00944 }
00945 max_tries--;
00946 } else
00947 break;
00948 }
00949
00951 if (chmod(sock_file, 0600) != 0)
00952 {
00953 perror("kdeinit4: Aborting. Can not set permissions on socket");
00954 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
00955 unlink(sock_file);
00956 close(d.wrapper);
00957 exit(255);
00958 }
00959
00960 if(listen(d.wrapper, SOMAXCONN) < 0)
00961 {
00962 perror("kdeinit4: Aborting. listen() failed");
00963 unlink(sock_file);
00964 close(d.wrapper);
00965 exit(255);
00966 }
00967 }
00968
00969
00970
00971
00972
00973 static int read_socket(int sock, char *buffer, int len)
00974 {
00975 ssize_t result;
00976 int bytes_left = len;
00977 while ( bytes_left > 0)
00978 {
00979 result = read(sock, buffer, bytes_left);
00980 if (result > 0)
00981 {
00982 buffer += result;
00983 bytes_left -= result;
00984 }
00985 else if (result == 0)
00986 return -1;
00987 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
00988 return -1;
00989 }
00990 return 0;
00991 }
00992
00993 static void start_klauncher()
00994 {
00995 if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) {
00996 perror("kdeinit4: socketpair() failed");
00997 exit(255);
00998 }
00999 char args[32];
01000 strcpy(args, "--fd=");
01001 sprintf(args + 5, "%d", d.launcher[1]);
01002 d.launcher_pid = launch( 2, "klauncher", args );
01003 close(d.launcher[1]);
01004 #ifndef NDEBUG
01005 fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n",
01006 (long) d.launcher_pid, d.result);
01007 #endif
01008 }
01009
01010 static void launcher_died()
01011 {
01012 if (!d.launcher_ok)
01013 {
01014
01015 fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
01016 ::exit(255);
01017 return;
01018 }
01019
01020
01021 #ifndef NDEBUG
01022 fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
01023 #endif
01024
01025 if (d.launcher_pid)
01026 {
01027 kill(d.launcher_pid, SIGKILL);
01028 sleep(1);
01029 }
01030
01031 d.launcher_ok = false;
01032 d.launcher_pid = 0;
01033 close(d.launcher[0]);
01034 d.launcher[0] = -1;
01035
01036 start_klauncher();
01037 }
01038
01039 static bool handle_launcher_request(int sock, const char *who)
01040 {
01041 (void)who;
01042
01043 klauncher_header request_header;
01044 char *request_data = 0L;
01045 int result = read_socket(sock, (char *) &request_header, sizeof(request_header));
01046 if (result != 0)
01047 {
01048 return false;
01049 }
01050
01051 if ( request_header.arg_length != 0 )
01052 {
01053 request_data = (char *) malloc(request_header.arg_length);
01054
01055 result = read_socket(sock, request_data, request_header.arg_length);
01056 if (result != 0)
01057 {
01058 free(request_data);
01059 return false;
01060 }
01061 }
01062
01063
01064 if (request_header.cmd == LAUNCHER_OK)
01065 {
01066 d.launcher_ok = true;
01067 }
01068 else if (request_header.arg_length &&
01069 ((request_header.cmd == LAUNCHER_EXEC) ||
01070 (request_header.cmd == LAUNCHER_EXT_EXEC) ||
01071 (request_header.cmd == LAUNCHER_SHELL ) ||
01072 (request_header.cmd == LAUNCHER_KWRAPPER) ||
01073 (request_header.cmd == LAUNCHER_EXEC_NEW)))
01074 {
01075 pid_t pid;
01076 klauncher_header response_header;
01077 long response_data;
01078 long l;
01079 memcpy( &l, request_data, sizeof( long ));
01080 int argc = l;
01081 const char *name = request_data + sizeof(long);
01082 const char *args = name + strlen(name) + 1;
01083 const char *cwd = 0;
01084 int envc = 0;
01085 const char *envs = 0;
01086 const char *tty = 0;
01087 int avoid_loops = 0;
01088 const char *startup_id_str = "0";
01089
01090 #ifndef NDEBUG
01091 fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n",
01092 commandToString(request_header.cmd),
01093 name, who);
01094 #endif
01095
01096 const char *arg_n = args;
01097 for(int i = 1; i < argc; i++)
01098 {
01099 arg_n = arg_n + strlen(arg_n) + 1;
01100 }
01101
01102 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER )
01103 {
01104
01105 cwd = arg_n; arg_n += strlen(cwd) + 1;
01106 }
01107 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01108 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01109 {
01110 memcpy( &l, arg_n, sizeof( long ));
01111 envc = l;
01112 arg_n += sizeof(long);
01113 envs = arg_n;
01114 for(int i = 0; i < envc; i++)
01115 {
01116 arg_n = arg_n + strlen(arg_n) + 1;
01117 }
01118 if( request_header.cmd == LAUNCHER_KWRAPPER )
01119 {
01120 tty = arg_n;
01121 arg_n += strlen( tty ) + 1;
01122 }
01123 }
01124
01125 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01126 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01127 {
01128 memcpy( &l, arg_n, sizeof( long ));
01129 avoid_loops = l;
01130 arg_n += sizeof( long );
01131 }
01132
01133 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01134 || request_header.cmd == LAUNCHER_EXT_EXEC )
01135 {
01136 startup_id_str = arg_n;
01137 arg_n += strlen( startup_id_str ) + 1;
01138 }
01139
01140 if ((request_header.arg_length > (arg_n - request_data)) &&
01141 (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ))
01142 {
01143
01144 cwd = arg_n; arg_n += strlen(cwd) + 1;
01145 }
01146
01147 if ((arg_n - request_data) != request_header.arg_length)
01148 {
01149 #ifndef NDEBUG
01150 fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n");
01151 #endif
01152 free(request_data);
01153 d.debug_wait = false;
01154 return true;
01155 }
01156
01157
01158 QByteArray olddisplay = qgetenv(DISPLAY);
01159 QByteArray kdedisplay = qgetenv("KDE_DISPLAY");
01160 bool reset_display = (! olddisplay.isEmpty() &&
01161 ! kdedisplay.isEmpty() &&
01162 olddisplay != kdedisplay);
01163
01164 if (reset_display)
01165 setenv(DISPLAY, kdedisplay, true);
01166
01167 pid = launch( argc, name, args, cwd, envc, envs,
01168 request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER,
01169 tty, avoid_loops, startup_id_str );
01170
01171 if (reset_display) {
01172 unsetenv("KDE_DISPLAY");
01173 setenv(DISPLAY, olddisplay, true);
01174 }
01175
01176 if (pid && (d.result == 0))
01177 {
01178 response_header.cmd = LAUNCHER_OK;
01179 response_header.arg_length = sizeof(response_data);
01180 response_data = pid;
01181 write(sock, &response_header, sizeof(response_header));
01182 write(sock, &response_data, response_header.arg_length);
01183
01184
01185 struct child *child = (struct child *) malloc(sizeof(struct child));
01186 child->pid = pid;
01187 child->sock = dup(sock);
01188 child->next = children;
01189 children = child;
01190 }
01191 else
01192 {
01193 int l = d.errorMsg.length();
01194 if (l) l++;
01195 response_header.cmd = LAUNCHER_ERROR;
01196 response_header.arg_length = l;
01197 write(sock, &response_header, sizeof(response_header));
01198 if (l)
01199 write(sock, d.errorMsg.data(), l);
01200 }
01201 d.debug_wait = false;
01202 }
01203 else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV)
01204 {
01205 const char *env_name;
01206 const char *env_value;
01207 env_name = request_data;
01208 env_value = env_name + strlen(env_name) + 1;
01209
01210 #ifndef NDEBUG
01211 fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who);
01212 #endif
01213
01214 if ( request_header.arg_length !=
01215 (int) (strlen(env_name) + strlen(env_value) + 2))
01216 {
01217 #ifndef NDEBUG
01218 fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n");
01219 #endif
01220 free(request_data);
01221 return true;
01222 }
01223 setenv( env_name, env_value, 1);
01224 }
01225 else if (request_header.cmd == LAUNCHER_TERMINATE_KDE)
01226 {
01227 #ifndef NDEBUG
01228 fprintf(stderr,"kdeinit4: terminate KDE.\n");
01229 #endif
01230 #ifdef Q_WS_X11
01231 kdeinit_xio_errhandler( 0L );
01232 #endif
01233 }
01234 else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT)
01235 {
01236 #ifndef NDEBUG
01237 fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid());
01238 #endif
01239 if (d.launcher_pid) {
01240 kill(d.launcher_pid, SIGTERM);
01241 d.launcher_pid = 0;
01242 close(d.launcher[0]);
01243 d.launcher[0] = -1;
01244 }
01245 unlink(sock_file);
01246 if (children) {
01247 close(d.wrapper);
01248 d.wrapper = -1;
01249 #ifndef NDEBUG
01250 fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n");
01251 #endif
01252 } else {
01253 raise(SIGTERM);
01254 }
01255 }
01256 else if (request_header.cmd == LAUNCHER_DEBUG_WAIT)
01257 {
01258 #ifndef NDEBUG
01259 fprintf(stderr,"kdeinit4: Debug wait activated.\n");
01260 #endif
01261 d.debug_wait = true;
01262 }
01263 if (request_data)
01264 free(request_data);
01265 return true;
01266 }
01267
01268 static void handle_requests(pid_t waitForPid)
01269 {
01270 int max_sock = d.deadpipe[0];
01271 if (d.wrapper > max_sock)
01272 max_sock = d.wrapper;
01273 if (d.launcher[0] > max_sock)
01274 max_sock = d.launcher[0];
01275 #ifdef Q_WS_X11
01276 if (X11fd > max_sock)
01277 max_sock = X11fd;
01278 #endif
01279 max_sock++;
01280
01281 while(1)
01282 {
01283 fd_set rd_set;
01284 fd_set wr_set;
01285 fd_set e_set;
01286 int result;
01287 pid_t exit_pid;
01288 int exit_status;
01289 char c;
01290
01291
01292 while( read(d.deadpipe[0], &c, 1) == 1)
01293 {}
01294
01295
01296 do {
01297 exit_pid = waitpid(-1, &exit_status, WNOHANG);
01298 if (exit_pid > 0)
01299 {
01300 #ifndef NDEBUG
01301 fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid);
01302 #endif
01303 if (waitForPid && (exit_pid == waitForPid))
01304 return;
01305
01306 if( WIFEXITED( exit_status ))
01307 exit_status = WEXITSTATUS(exit_status);
01308 else if( WIFSIGNALED( exit_status ))
01309 exit_status = 128 + WTERMSIG( exit_status );
01310 child_died(exit_pid, exit_status);
01311
01312 if (d.wrapper < 0 && !children) {
01313 #ifndef NDEBUG
01314 fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n",
01315 (long) getpid());
01316 #endif
01317 raise(SIGTERM);
01318 }
01319 }
01320 }
01321 while( exit_pid > 0);
01322
01323 FD_ZERO(&rd_set);
01324 FD_ZERO(&wr_set);
01325 FD_ZERO(&e_set);
01326
01327 if (d.launcher[0] >= 0)
01328 FD_SET(d.launcher[0], &rd_set);
01329 if (d.wrapper >= 0)
01330 FD_SET(d.wrapper, &rd_set);
01331 FD_SET(d.deadpipe[0], &rd_set);
01332 #ifdef Q_WS_X11
01333 if(X11fd >= 0) FD_SET(X11fd, &rd_set);
01334 #endif
01335
01336 result = select(max_sock, &rd_set, &wr_set, &e_set, 0);
01337 if (result < 0) {
01338 if (errno == EINTR || errno == EAGAIN)
01339 continue;
01340 perror("kdeinit4: Aborting. select() failed");
01341 return;
01342 }
01343
01344
01345 if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set))
01346 {
01347 struct sockaddr_un client;
01348 kde_socklen_t sClient = sizeof(client);
01349 int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient);
01350 if (sock >= 0)
01351 {
01352 d.accepted_fd = sock;
01353 handle_launcher_request(sock, "wrapper");
01354 close(sock);
01355 d.accepted_fd = -1;
01356 }
01357 }
01358
01359
01360 if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set))
01361 {
01362 if (!handle_launcher_request(d.launcher[0], "launcher"))
01363 launcher_died();
01364 if (waitForPid == d.launcher_pid)
01365 return;
01366 }
01367
01368 #ifdef Q_WS_X11
01369
01370 if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) {
01371 if (X11display != 0) {
01372 XEvent event_return;
01373 while (XPending(X11display))
01374 XNextEvent(X11display, &event_return);
01375 }
01376 }
01377 #endif
01378 }
01379 }
01380
01381 static void kdeinit_library_path()
01382 {
01383 const QStringList ltdl_library_path =
01384 QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(QLatin1Char(':'),QString::SkipEmptyParts);
01385 #ifdef Q_OS_DARWIN
01386 const QByteArray ldlibpath = qgetenv("DYLD_LIBRARY_PATH");
01387 #else
01388 const QByteArray ldlibpath = qgetenv("LD_LIBRARY_PATH");
01389 #endif
01390 const QStringList ld_library_path =
01391 QFile::decodeName(ldlibpath).split(QLatin1Char(':'),QString::SkipEmptyParts);
01392
01393 QByteArray extra_path;
01394 const QStringList candidates = s_instance->dirs()->resourceDirs("lib");
01395 for (QStringList::ConstIterator it = candidates.begin();
01396 it != candidates.end();
01397 ++it)
01398 {
01399 QString d = *it;
01400 if (ltdl_library_path.contains(d))
01401 continue;
01402 if (ld_library_path.contains(d))
01403 continue;
01404 if (d[d.length()-1] == QLatin1Char('/'))
01405 {
01406 d.truncate(d.length()-1);
01407 if (ltdl_library_path.contains(d))
01408 continue;
01409 if (ld_library_path.contains(d))
01410 continue;
01411 }
01412 if ((d == QLatin1String("/lib")) || (d == QLatin1String("/usr/lib")))
01413 continue;
01414
01415 QByteArray dir = QFile::encodeName(d);
01416
01417 if (access(dir, R_OK))
01418 continue;
01419
01420 if ( !extra_path.isEmpty())
01421 extra_path += ':';
01422 extra_path += dir;
01423 }
01424
01425
01426
01427
01428 QByteArray display = qgetenv(DISPLAY);
01429 if (display.isEmpty())
01430 {
01431 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
01432 fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n");
01433 exit(255);
01434 #endif
01435 }
01436 int i;
01437 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
01438 display.truncate(i);
01439
01440 display.replace(':','_');
01441 #ifdef __APPLE__
01442 display.replace('/','_');
01443 #endif
01444
01445 const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display));
01446 QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", socketFileName, *s_instance));
01447 if (socketName.length() >= MAX_SOCK_FILE)
01448 {
01449 fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
01450 fprintf(stderr, " '%s'\n", socketName.data());
01451 exit(255);
01452 }
01453 strcpy(sock_file, socketName.data());
01454 }
01455
01456 int kdeinit_xio_errhandler( Display *disp )
01457 {
01458
01459
01460 if ( disp )
01461 qWarning( "kdeinit4: Fatal IO error: client killed" );
01462
01463 if (sock_file[0])
01464 {
01466 unlink(sock_file);
01467 }
01468
01469
01470 if (d.suicide)
01471 {
01472 if (d.launcher_pid)
01473 kill(d.launcher_pid, SIGTERM);
01474 if (d.kded_pid)
01475 kill(d.kded_pid, SIGTERM);
01476 exit( 0 );
01477 }
01478
01479 if ( disp )
01480 qWarning( "kdeinit4: sending SIGHUP to children." );
01481
01482
01483 KDE_signal(SIGHUP, SIG_IGN);
01484 kill(0, SIGHUP);
01485
01486 sleep(2);
01487
01488 if ( disp )
01489 qWarning( "kdeinit4: sending SIGTERM to children." );
01490
01491
01492 KDE_signal(SIGTERM, SIG_IGN);
01493 kill(0, SIGTERM);
01494
01495 if ( disp )
01496 qWarning( "kdeinit4: Exit." );
01497
01498 exit( 0 );
01499 return 0;
01500 }
01501
01502 #ifdef Q_WS_X11
01503 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err )
01504 {
01505 #ifndef NDEBUG
01506 char errstr[256];
01507
01508 XGetErrorText( dpy, err->error_code, errstr, 256 );
01509 fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n"
01510 " Major opcode: %d\n"
01511 " Minor opcode: %d\n"
01512 " Resource id: 0x%lx\n",
01513 getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid );
01514
01515
01516
01517 #else
01518 Q_UNUSED(dpy);
01519 Q_UNUSED(err);
01520 #endif
01521 return 0;
01522 }
01523 #endif
01524
01525 #ifdef Q_WS_X11
01526
01527
01528 static void setupX()
01529 {
01530 XSetIOErrorHandler(kdeinit_xio_errhandler);
01531 XSetErrorHandler(kdeinit_x_errhandler);
01532 }
01533
01534
01535 static int initXconnection()
01536 {
01537 X11display = XOpenDisplay(NULL);
01538 if ( X11display != 0 ) {
01539 XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \
01540 0,
01541 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)),
01542 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) );
01543 #ifndef NDEBUG
01544 fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display));
01545 #endif
01546 int fd = XConnectionNumber( X11display );
01547 int on = 1;
01548 (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on));
01549 return fd;
01550 } else
01551 fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \
01552 "kdeinit4: Might not terminate at end of session.\n");
01553
01554 return -1;
01555 }
01556 #endif
01557
01558 extern "C" {
01559
01560 static void secondary_child_handler(int)
01561 {
01562 waitpid(-1, 0, WNOHANG);
01563 }
01564
01565 }
01566
01567 int main(int argc, char **argv, char **envp)
01568 {
01569 setlocale (LC_ALL, "");
01570 setlocale (LC_NUMERIC, "C");
01571
01572 pid_t pid;
01573 bool do_fork = true;
01574 int launch_klauncher = 1;
01575 int launch_kded = 1;
01576 int keep_running = 1;
01577 d.suicide = false;
01578
01580 char **safe_argv = (char **) malloc( sizeof(char *) * argc);
01581 for(int i = 0; i < argc; i++)
01582 {
01583 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
01584 if (strcmp(safe_argv[i], "--no-klauncher") == 0)
01585 launch_klauncher = 0;
01586 if (strcmp(safe_argv[i], "--no-kded") == 0)
01587 launch_kded = 0;
01588 #ifdef Q_WS_MACX
01589
01590 if (strcmp(safe_argv[i], "--nofork") == 0)
01591 #else
01592 if (strcmp(safe_argv[i], "--no-fork") == 0)
01593 #endif
01594 do_fork = false;
01595 if (strcmp(safe_argv[i], "--suicide") == 0)
01596 d.suicide = true;
01597 if (strcmp(safe_argv[i], "--exit") == 0)
01598 keep_running = 0;
01599 if (strcmp(safe_argv[i], "--version") == 0)
01600 {
01601 printf("Qt: %s\n", qVersion());
01602 printf("KDE: %s\n", KDE_VERSION_STRING);
01603 exit(0);
01604 }
01605 if (strcmp(safe_argv[i], "--help") == 0)
01606 {
01607 printf("Usage: kdeinit4 [options]\n");
01608
01609 #ifdef Q_WS_MACX
01610 printf(" --nofork Do not fork\n");
01611 #else
01612 printf(" --no-fork Do not fork\n");
01613 #endif
01614
01615 printf(" --no-kded Do not start kded\n");
01616 printf(" --suicide Terminate when no KDE applications are left running\n");
01617 printf(" --version Show version information\n");
01618
01619 exit(0);
01620 }
01621 }
01622
01623 cleanup_fds();
01624
01625 if (do_fork) {
01626 #ifdef Q_WS_MACX
01627 mac_fork_and_reexec_self();
01628 #else
01629 if (pipe(d.initpipe) != 0) {
01630 perror("kdeinit4: pipe failed");
01631 return 1;
01632 }
01633
01634
01635
01636
01637 KDE_signal( SIGCHLD, secondary_child_handler);
01638 if (fork() > 0)
01639 {
01640 close(d.initpipe[1]);
01641 d.initpipe[1] = -1;
01642
01643 char c;
01644 while( read(d.initpipe[0], &c, 1) < 0)
01645 ;
01646
01647 close(d.initpipe[0]);
01648 d.initpipe[0] = -1;
01649 return 0;
01650 }
01651 close(d.initpipe[0]);
01652 d.initpipe[0] = -1;
01653 #endif
01654 }
01655
01657 if(keep_running)
01658 setsid();
01659
01661 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
01662
01664 #ifndef SKIP_PROCTITLE
01665 proctitle_init(argc, argv, envp);
01666 #endif
01667
01668 kdeinit_library_path();
01669
01670
01671
01672 Q_ASSERT(!KGlobal::hasMainComponent());
01673
01674 unsetenv("LD_BIND_NOW");
01675 unsetenv("DYLD_BIND_AT_LAUNCH");
01676 KApplication::loadedByKdeinit = true;
01677
01678 d.maxname = strlen(argv[0]);
01679 d.launcher_pid = 0;
01680 d.kded_pid = 0;
01681 d.wrapper = -1;
01682 d.accepted_fd = -1;
01683 d.debug_wait = false;
01684 d.launcher_ok = false;
01685 children = NULL;
01686 init_signals();
01687 #ifdef Q_WS_X11
01688 setupX();
01689 #endif
01690
01691 if (keep_running)
01692 {
01693
01694
01695
01696
01697 init_kdeinit_socket();
01698 }
01699 #ifdef Q_WS_X11
01700 if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty())
01701 {
01702 #ifdef __KDE_HAVE_GCC_VISIBILITY
01703 QString extra = KStandardDirs::locate("lib", QLatin1String("libplasma.so.3"), *s_instance);
01704 #else
01705 QString extra;
01706 #endif
01707
01708
01709 if (!extra.isEmpty()) {
01710 QLibrary l(extra);
01711 l.setLoadHints(QLibrary::ExportExternalSymbolsHint);
01712 l.load();
01713 }
01714 }
01715 #endif
01716 if (launch_klauncher)
01717 {
01718 start_klauncher();
01719 handle_requests(d.launcher_pid);
01720 }
01721
01722 #ifdef Q_WS_X11
01723 X11fd = initXconnection();
01724 #endif
01725
01726 {
01727 QFont::initialize();
01728 #ifdef Q_WS_X11
01729 if (XSupportsLocale ())
01730 {
01731
01732
01733 XOpenIM (X11display, 0, 0, 0);
01734 }
01735 #endif
01736 }
01737
01738 if (launch_kded)
01739 {
01740 pid = launch( 1, KDED_EXENAME, 0 );
01741 #ifndef NDEBUG
01742 fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result);
01743 #endif
01744 d.kded_pid = pid;
01745 handle_requests(pid);
01746 }
01747
01748 for(int i = 1; i < argc; i++)
01749 {
01750 if (safe_argv[i][0] == '+')
01751 {
01752 pid = launch( 1, safe_argv[i]+1, 0);
01753 #ifndef NDEBUG
01754 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result);
01755 #endif
01756 handle_requests(pid);
01757 }
01758 else if (safe_argv[i][0] == '-')
01759 {
01760
01761 }
01762 else
01763 {
01764 pid = launch( 1, safe_argv[i], 0 );
01765 #ifndef NDEBUG
01766 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result);
01767 #endif
01768 }
01769 }
01770
01772 for(int i = 0; i < argc; i++)
01773 {
01774 free(safe_argv[i]);
01775 }
01776 free (safe_argv);
01777
01778 #ifndef SKIP_PROCTITLE
01779 proctitle_set("kdeinit4 Running...");
01780 #endif
01781
01782 if (!keep_running)
01783 return 0;
01784
01785 if (d.initpipe[1] != -1)
01786 {
01787 char c = 0;
01788 write(d.initpipe[1], &c, 1);
01789 close(d.initpipe[1]);
01790 d.initpipe[1] = -1;
01791 }
01792
01793 handle_requests(0);
01794
01795 return 0;
01796 }
01797
01798