00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <sys/types.h>
00025 #include <sys/time.h>
00026 #include <sys/stat.h>
00027 #include <sys/socket.h>
00028 #include <sys/un.h>
00029 #include <sys/wait.h>
00030 #ifdef HAVE_SYS_SELECT_H
00031 #include <sys/select.h>
00032 #endif
00033
00034 #include <errno.h>
00035 #include <fcntl.h>
00036 #include "proctitle.h"
00037 #include <signal.h>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include <unistd.h>
00042 #include <locale.h>
00043
00044 #include <QtCore/QLibrary>
00045 #include <QtCore/QString>
00046 #include <QtCore/QFile>
00047 #include <QtCore/QDate>
00048 #include <QtCore/QFileInfo>
00049 #include <QtCore/QTextStream>
00050 #include <QtCore/QRegExp>
00051 #include <QtGui/QFont>
00052 #include <QDir>
00053 #include <kcomponentdata.h>
00054 #include <kstandarddirs.h>
00055 #include <kconfiggroup.h>
00056 #include <kglobal.h>
00057 #include <kconfig.h>
00058 #include <klibloader.h>
00059 #include <kapplication.h>
00060 #include <klocale.h>
00061 #include <kdebug.h>
00062 #include <kde_file.h>
00063
00064 #ifdef Q_OS_LINUX
00065 #include <sys/prctl.h>
00066 #ifndef PR_SET_NAME
00067 #define PR_SET_NAME 15
00068 #endif
00069 #endif
00070
00071 #ifdef Q_WS_MACX
00072 #include <kkernel_mac.h>
00073 #endif
00074
00075 #include <kdeversion.h>
00076
00077 #include "klauncher_cmds.h"
00078
00079 #ifdef Q_WS_X11
00080 #include <X11/Xlib.h>
00081 #include <X11/Xatom.h>
00082 #include <fixx11h.h>
00083 #include <kstartupinfo.h>
00084 #endif
00085
00086 #if KDE_IS_VERSION( 3, 90, 0 )
00087 #ifdef __GNUC__
00088 #warning Check if Linux OOM-killer still sucks and if yes, forwardport revision 579164 and following fixes.
00089 #endif
00090 #endif
00091
00092 extern char **environ;
00093
00094 #ifdef Q_WS_X11
00095 static int X11fd = -1;
00096 static Display *X11display = 0;
00097 static int X11_startup_notify_fd = -1;
00098 static Display *X11_startup_notify_display = 0;
00099 #endif
00100 static KComponentData *s_instance = 0;
00101 #define MAX_SOCK_FILE 255
00102 static char sock_file[MAX_SOCK_FILE];
00103
00104
00105 #ifdef Q_WS_X11
00106 #define DISPLAY "DISPLAY"
00107 #elif defined(Q_WS_QWS)
00108 #define DISPLAY "QWS_DISPLAY"
00109 #elif defined(Q_WS_MACX)
00110 #define DISPLAY "MAC_DISPLAY"
00111 #elif defined(Q_WS_WIN)
00112 #define DISPLAY "WIN_DISPLAY"
00113 #else
00114 #error Use QT/X11 or QT/Embedded
00115 #endif
00116
00117
00118 static struct {
00119 int maxname;
00120 int fd[2];
00121 int launcher[2];
00122 int deadpipe[2];
00123 int initpipe[2];
00124 int wrapper;
00125 int wrapper_old;
00126 int accepted_fd;
00127 char result;
00128 int exit_status;
00129 pid_t fork;
00130 pid_t launcher_pid;
00131 pid_t kded_pid;
00132 pid_t my_pid;
00133 int n;
00134 char **argv;
00135 int (*func)(int, char *[]);
00136 int (*launcher_func)(int);
00137 bool debug_wait;
00138 QByteArray errorMsg;
00139 bool launcher_ok;
00140 bool suicide;
00141 } d;
00142
00143 struct child
00144 {
00145 pid_t pid;
00146 int sock;
00147 struct child *next;
00148 };
00149
00150 static struct child *children;
00151
00152 #ifdef Q_WS_X11
00153 extern "C" {
00154 int kdeinit_xio_errhandler( Display * );
00155 int kdeinit_x_errhandler( Display *, XErrorEvent *err );
00156 }
00157 #endif
00158
00159
00160 #include <kparts/plugin.h>
00161 extern "C" KParts::Plugin* _kinit_init_kparts() { return new KParts::Plugin(); }
00162
00163 #include <kio/authinfo.h>
00164 extern "C" KIO::AuthInfo* _kioslave_init_kio() { return new KIO::AuthInfo(); }
00165
00166
00167
00168
00169
00170
00171
00172
00173 static void cleanup_fds()
00174 {
00175 for (int fd = 3; fd < FD_SETSIZE; ++fd)
00176 close(fd);
00177 }
00178
00179
00180
00181
00182
00183 static void close_fds()
00184 {
00185 if (d.deadpipe[0] != -1)
00186 {
00187 close(d.deadpipe[0]);
00188 d.deadpipe[0] = -1;
00189 }
00190
00191 if (d.deadpipe[1] != -1)
00192 {
00193 close(d.deadpipe[1]);
00194 d.deadpipe[1] = -1;
00195 }
00196
00197 if (d.initpipe[0] != -1)
00198 {
00199 close(d.initpipe[0]);
00200 d.initpipe[0] = -1;
00201 }
00202
00203 if (d.initpipe[1] != -1)
00204 {
00205 close(d.initpipe[1]);
00206 d.initpipe[1] = -1;
00207 }
00208
00209 if (d.launcher_pid)
00210 {
00211 close(d.launcher[0]);
00212 d.launcher_pid = 0;
00213 }
00214 if (d.wrapper != -1)
00215 {
00216 close(d.wrapper);
00217 d.wrapper = -1;
00218 }
00219 if (d.wrapper_old != -1)
00220 {
00221 close(d.wrapper_old);
00222 d.wrapper_old = -1;
00223 }
00224 if (d.accepted_fd != -1)
00225 {
00226 close(d.accepted_fd);
00227 d.accepted_fd = -1;
00228 }
00229 #ifdef Q_WS_X11
00230 if (X11fd >= 0)
00231 {
00232 close(X11fd);
00233 X11fd = -1;
00234 }
00235 if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd )
00236 {
00237 close(X11_startup_notify_fd);
00238 X11_startup_notify_fd = -1;
00239 }
00240 #endif
00241
00242 KDE_signal(SIGCHLD, SIG_DFL);
00243 KDE_signal(SIGPIPE, SIG_DFL);
00244 }
00245
00246
00247 static void child_died(pid_t exit_pid, int exit_status)
00248 {
00249 struct child *child = children;
00250 struct child *prev = NULL;
00251
00252 while (child)
00253 {
00254 if (child->pid == exit_pid)
00255 {
00256
00257 klauncher_header request_header;
00258 long request_data[2];
00259 request_header.cmd = LAUNCHER_DIED;
00260 request_header.arg_length = sizeof(long) * 2;
00261 request_data[0] = exit_pid;
00262 request_data[1] = exit_status;
00263 write(child->sock, &request_header, sizeof(request_header));
00264 write(child->sock, request_data, request_header.arg_length);
00265 close(child->sock);
00266
00267 if (prev)
00268 {
00269 prev->next = child->next;
00270 }
00271 else
00272 {
00273 child = NULL;
00274 }
00275 free(child);
00276 return;
00277 }
00278
00279 prev = child;
00280 child = child->next;
00281 }
00282 }
00283
00284
00285 static void exitWithErrorMsg(const QString &errorMsg)
00286 {
00287 fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() );
00288 QByteArray utf8ErrorMsg = errorMsg.toUtf8();
00289 d.result = 3;
00290 write(d.fd[1], &d.result, 1);
00291 int l = utf8ErrorMsg.length();
00292 write(d.fd[1], &l, sizeof(int));
00293 write(d.fd[1], utf8ErrorMsg.data(), l);
00294 close(d.fd[1]);
00295 exit(255);
00296 }
00297
00298 static void setup_tty( const char* tty )
00299 {
00300 if( tty == NULL || *tty == '\0' )
00301 return;
00302 int fd = KDE_open( tty, O_WRONLY );
00303 if( fd < 0 )
00304 {
00305 perror( "kdeinit4: could not open() tty" );
00306 return;
00307 }
00308 if( dup2( fd, STDOUT_FILENO ) < 0 )
00309 {
00310 perror( "kdeinit4: could not dup2() tty" );
00311 close( fd );
00312 return;
00313 }
00314 if( dup2( fd, STDERR_FILENO ) < 0 )
00315 {
00316 perror( "kdeinit4: could not dup2() tty" );
00317 close( fd );
00318 return;
00319 }
00320 close( fd );
00321 }
00322
00323
00324 static int get_current_desktop( Display* disp )
00325 {
00326 int desktop = 0;
00327 #ifdef Q_WS_X11 // Only X11 supports multiple desktops
00328 Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False );
00329 Atom type_ret;
00330 int format_ret;
00331 unsigned char *data_ret;
00332 unsigned long nitems_ret, unused;
00333 if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop,
00334 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret )
00335 == Success)
00336 {
00337 if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1)
00338 desktop = *((long *) data_ret) + 1;
00339 if (data_ret)
00340 XFree ((char*) data_ret);
00341 }
00342 #endif
00343 return desktop;
00344 }
00345
00346
00347 const char* get_env_var( const char* var, int envc, const char* envs )
00348 {
00349 if( envc > 0 )
00350 {
00351 const char* env_l = envs;
00352 int ln = strlen( var );
00353 for (int i = 0; i < envc; i++)
00354 {
00355 if( strncmp( env_l, var, ln ) == 0 )
00356 return env_l + ln;
00357 while(*env_l != 0) env_l++;
00358 env_l++;
00359 }
00360 }
00361 return NULL;
00362 }
00363
00364 #ifdef Q_WS_X11
00365 static void init_startup_info( KStartupInfoId& id, const char* bin,
00366 int envc, const char* envs )
00367 {
00368 const char* dpy = get_env_var( DISPLAY"=", envc, envs );
00369
00370
00371 X11_startup_notify_display = XOpenDisplay( dpy );
00372 if( X11_startup_notify_display == NULL )
00373 return;
00374 X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display );
00375 KStartupInfoData data;
00376 int desktop = get_current_desktop( X11_startup_notify_display );
00377 data.setDesktop( desktop );
00378 data.setBin( bin );
00379 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
00380 XFlush( X11_startup_notify_display );
00381 }
00382
00383 static void complete_startup_info( KStartupInfoId& id, pid_t pid )
00384 {
00385 if( X11_startup_notify_display == NULL )
00386 return;
00387 if( pid == 0 )
00388 KStartupInfo::sendFinishX( X11_startup_notify_display, id );
00389 else
00390 {
00391 KStartupInfoData data;
00392 data.addPid( pid );
00393 data.setHostname();
00394 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
00395 }
00396 XCloseDisplay( X11_startup_notify_display );
00397 X11_startup_notify_display = NULL;
00398 X11_startup_notify_fd = -1;
00399 }
00400 #endif
00401
00402 QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops )
00403 {
00404 QStringList paths;
00405 if( envc > 0 )
00406 {
00407 const char* path = get_env_var( "PATH=", envc, envs );
00408 if( path != NULL )
00409 paths = QString(path).split( QRegExp( "[:\b]" ));
00410 }
00411 else
00412 paths = QString::fromLocal8Bit( qgetenv("PATH") ).split( QRegExp( "[:\b]" ), QString::KeepEmptyParts );
00413 QByteArray execpath = QFile::encodeName(
00414 s_instance->dirs()->findExe( exec, paths.join( QLatin1String( ":" ))));
00415 if( avoid_loops && !execpath.isEmpty())
00416 {
00417 int pos = execpath.lastIndexOf( '/' );
00418 QString bin_path = execpath.left( pos );
00419 for( QStringList::Iterator it = paths.begin();
00420 it != paths.end();
00421 ++it )
00422 if( ( *it ) == bin_path || ( *it ) == bin_path + '/' )
00423 {
00424 paths.erase( it );
00425 break;
00426 }
00427 execpath = QFile::encodeName(
00428 s_instance->dirs()->findExe( exec, paths.join( QString( ":" ))));
00429 }
00430 return execpath;
00431 }
00432
00433 static pid_t launch(int argc, const char *_name, const char *args,
00434 const char *cwd=0, int envc=0, const char *envs=0,
00435 bool reset_env = false,
00436 const char *tty=0, bool avoid_loops = false,
00437 const char* startup_id_str = "0" )
00438 {
00439 int launcher = 0;
00440 QByteArray lib;
00441 QByteArray name;
00442 QByteArray exec;
00443
00444 if (strcmp(_name, "klauncher") == 0) {
00445
00446
00447
00448 if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher))
00449 {
00450 perror("kdeinit4: socketpair() failed!\n");
00451 exit(255);
00452 }
00453 launcher = 1;
00454 }
00455
00456 QByteArray libpath;
00457 QByteArray execpath;
00458 if (_name[0] != '/')
00459 {
00460 lib = name = _name;
00461 exec = name;
00462 libpath = QFile::encodeName(KLibLoader::findLibrary(lib.constData(), *s_instance));
00463 execpath = execpath_avoid_loops( exec, envc, envs, avoid_loops );
00464 }
00465 else
00466 {
00467 lib = _name;
00468 name = _name;
00469 name = name.mid( name.lastIndexOf('/') + 1);
00470 exec = _name;
00471 if (lib.endsWith(".la"))
00472 libpath = lib;
00473 else
00474 execpath = exec;
00475 }
00476 fprintf(stderr,"kdeinit4: preparing to launch %s\n", execpath.constData());
00477 if (!args)
00478 {
00479 argc = 1;
00480 }
00481
00482 if (0 > pipe(d.fd))
00483 {
00484 perror("kdeinit4: pipe() failed!\n");
00485 d.result = 3;
00486 d.errorMsg = i18n("Unable to start new process.\n"
00487 "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();
00488 d.fork = 0;
00489 return d.fork;
00490 }
00491
00492 #ifdef Q_WS_X11
00493 KStartupInfoId startup_id;
00494 startup_id.initId( startup_id_str );
00495 if( !startup_id.none())
00496 init_startup_info( startup_id, name, envc, envs );
00497 #endif
00498
00499 d.errorMsg = 0;
00500 d.fork = fork();
00501 switch(d.fork) {
00502 case -1:
00503 perror("kdeinit4: fork() failed!\n");
00504 d.result = 3;
00505 d.errorMsg = i18n("Unable to create new process.\n"
00506 "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();
00507 close(d.fd[0]);
00508 close(d.fd[1]);
00509 d.fork = 0;
00510 break;
00511 case 0:
00512 {
00514 close(d.fd[0]);
00515 close_fds();
00516 if (launcher)
00517 {
00518 if (d.fd[1] == LAUNCHER_FD)
00519 {
00520 d.fd[1] = dup(d.fd[1]);
00521 }
00522 if (d.launcher[1] != LAUNCHER_FD)
00523 {
00524 dup2( d.launcher[1], LAUNCHER_FD);
00525 close( d.launcher[1] );
00526 }
00527 close( d.launcher[0] );
00528 }
00529
00530 if (cwd && *cwd)
00531 chdir(cwd);
00532 else {
00533
00534
00535
00536 KConfigGroup g(s_instance->config(), "Paths");
00537 const QString documentPath = g.readPathEntry("Documents",
00538 #ifdef Q_WS_WIN
00539 getWin32ShellFoldersPath("Personal")
00540 #else
00541 QDir::homePath());
00542 #endif
00543 const QByteArray docPath = QFile::encodeName(documentPath);
00544 chdir(docPath.constData());
00545 }
00546
00547 if( reset_env )
00548 {
00549
00550 QList<QByteArray> unset_envs;
00551 for( int tmp_env_count = 0;
00552 environ[tmp_env_count];
00553 tmp_env_count++)
00554 unset_envs.append( environ[ tmp_env_count ] );
00555 foreach(const QByteArray &tmp, unset_envs)
00556 {
00557 int pos = tmp.indexOf( '=' );
00558 if( pos >= 0 )
00559 unsetenv( tmp.left( pos ));
00560 }
00561 }
00562
00563 for (int i = 0; i < envc; i++)
00564 {
00565 putenv((char *)envs);
00566 while(*envs != 0) envs++;
00567 envs++;
00568 }
00569
00570 #ifdef Q_WS_X11
00571 if( startup_id.none())
00572 KStartupInfo::resetStartupEnv();
00573 else
00574 startup_id.setupStartupEnv();
00575 #endif
00576 {
00577 int r;
00578 QByteArray procTitle;
00579 d.argv = (char **) malloc(sizeof(char *) * (argc+1));
00580 d.argv[0] = (char *) _name;
00581 #ifdef Q_WS_MAC
00582 QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0]));
00583 if (!argvexe.isEmpty()) {
00584 QByteArray cstr = argvexe.toLocal8Bit();
00585 kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data();
00586 d.argv[0] = strdup(cstr.data());
00587 }
00588 #endif
00589 for (int i = 1; i < argc; i++)
00590 {
00591 d.argv[i] = (char *) args;
00592 procTitle += ' ';
00593 procTitle += (char *) args;
00594 while(*args != 0) args++;
00595 args++;
00596 }
00597 d.argv[argc] = 0;
00598
00600 #ifdef Q_OS_LINUX
00601
00602 r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0);
00603 if ( r == 0 )
00604 proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00605 else
00606 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00607 #else
00608 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
00609 #endif
00610 }
00611
00612 if (libpath.isEmpty() && execpath.isEmpty())
00613 {
00614 QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name));
00615 exitWithErrorMsg(errorMsg);
00616 }
00617
00618
00619 if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty() && !launcher)
00620 libpath.truncate(0);
00621
00622 QLibrary l(libpath);
00623
00624 if ( !libpath.isEmpty() )
00625 {
00626 if (!l.load() || !l.isLoaded() )
00627 {
00628 QString ltdlError (l.errorString());
00629 if (execpath.isEmpty())
00630 {
00631
00632 QString errorMsg = i18n("Could not open library '%1'.\n%2", QFile::decodeName(libpath), ltdlError);
00633 exitWithErrorMsg(errorMsg);
00634 }
00635 else
00636 {
00637
00638 fprintf(stderr, "Could not open library %s: %s\n", lib.data(),
00639 qPrintable(ltdlError) );
00640 }
00641 }
00642 }
00643 if (!l.isLoaded())
00644 {
00645 d.result = 2;
00646 write(d.fd[1], &d.result, 1);
00647
00648
00649
00650 fcntl(d.fd[1], F_SETFD, FD_CLOEXEC);
00651
00652 setup_tty( tty );
00653
00654 QByteArray executable = execpath.data();
00655 #ifdef Q_WS_MAC
00656 QString bundlepath = s_instance->dirs()->findExe( execpath.data() );
00657 if (!bundlepath.isEmpty())
00658 executable = QFile::encodeName(bundlepath);
00659 #endif
00660
00661 if (!executable.isEmpty())
00662 execvp(executable, d.argv);
00663
00664 d.result = 1;
00665 write(d.fd[1], &d.result, 1);
00666 close(d.fd[1]);
00667 exit(255);
00668 }
00669
00670 void * sym = l.resolve( "kdeinitmain");
00671 if (!sym )
00672 {
00673 sym = l.resolve( "kdemain" );
00674 if ( !sym )
00675 {
00676 QString ltdlError = l.errorString();
00677 fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) );
00678 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2",
00679 QLatin1String(libpath), ltdlError);
00680 exitWithErrorMsg(errorMsg);
00681 }
00682 }
00683
00684 d.result = 0;
00685 write(d.fd[1], &d.result, 1);
00686 close(d.fd[1]);
00687
00688 d.func = (int (*)(int, char *[])) sym;
00689 if (d.debug_wait)
00690 {
00691 fprintf(stderr, "kdeinit4: Suspending process\n"
00692 "kdeinit4: 'gdb kdeinit4 %d' to debug\n"
00693 "kdeinit4: 'kill -SIGCONT %d' to continue\n",
00694 getpid(), getpid());
00695 kill(getpid(), SIGSTOP);
00696 }
00697 else
00698 {
00699 setup_tty( tty );
00700 }
00701
00702 exit( d.func(argc, d.argv));
00703
00704 break;
00705 }
00706 default:
00708 close(d.fd[1]);
00709 if (launcher)
00710 {
00711 close(d.launcher[1]);
00712 d.launcher_pid = d.fork;
00713 }
00714 bool exec = false;
00715 for(;;)
00716 {
00717 d.n = read(d.fd[0], &d.result, 1);
00718 if (d.n == 1)
00719 {
00720 if (d.result == 2)
00721 {
00722 #ifndef NDEBUG
00723
00724 #endif
00725 exec = true;
00726 continue;
00727 }
00728 if (d.result == 3)
00729 {
00730 int l = 0;
00731 d.n = read(d.fd[0], &l, sizeof(int));
00732 if (d.n == sizeof(int))
00733 {
00734 QByteArray tmp;
00735 tmp.resize(l+1);
00736 d.n = read(d.fd[0], tmp.data(), l);
00737 tmp[l] = 0;
00738 if (d.n == l)
00739 d.errorMsg = tmp;
00740 }
00741 }
00742
00743 break;
00744 }
00745 if (d.n == -1)
00746 {
00747 if (errno == ECHILD) {
00748 continue;
00749 }
00750 if (errno == EINTR || errno == EAGAIN) {
00751 continue;
00752 }
00753 }
00754 if (exec)
00755 {
00756 d.result = 0;
00757 break;
00758 }
00759 if (d.n == 0)
00760 {
00761 fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData());
00762 perror("kdeinit4: Pipe closed unexpectedly");
00763 d.result = 1;
00764 break;
00765 }
00766 perror("kdeinit4: Error reading from pipe");
00767 d.result = 1;
00768 break;
00769 }
00770 close(d.fd[0]);
00771 if (launcher && (d.result == 0))
00772 {
00773
00774 d.launcher_pid = d.fork;
00775 }
00776 }
00777 #ifdef Q_WS_X11
00778 if( !startup_id.none())
00779 {
00780 if( d.fork && d.result == 0 )
00781 complete_startup_info( startup_id, d.fork );
00782 else
00783 complete_startup_info( startup_id, 0 );
00784 }
00785 #endif
00786 return d.fork;
00787 }
00788
00789 static void sig_child_handler(int)
00790 {
00791
00792
00793
00794
00795
00796
00797
00798
00799 char c = 0;
00800 write(d.deadpipe[1], &c, 1);
00801 }
00802
00803 static void init_signals()
00804 {
00805 struct sigaction act;
00806 long options;
00807
00808 if (pipe(d.deadpipe) != 0)
00809 {
00810 perror("kdeinit4: Aborting. Can not create pipe: ");
00811 exit(255);
00812 }
00813
00814 options = fcntl(d.deadpipe[0], F_GETFL);
00815 if (options == -1)
00816 {
00817 perror("kdeinit4: Aborting. Can not make pipe non-blocking: ");
00818 exit(255);
00819 }
00820
00821 if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1)
00822 {
00823 perror("kdeinit4: Aborting. Can not make pipe non-blocking: ");
00824 exit(255);
00825 }
00826
00827
00828
00829
00830
00831
00832 act.sa_handler=sig_child_handler;
00833 sigemptyset(&(act.sa_mask));
00834 sigaddset(&(act.sa_mask), SIGCHLD);
00835 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00836 act.sa_flags = SA_NOCLDSTOP;
00837
00838
00839
00840
00841 #ifdef SA_RESTART
00842 act.sa_flags |= SA_RESTART;
00843 #endif
00844 sigaction( SIGCHLD, &act, 0L);
00845
00846 act.sa_handler=SIG_IGN;
00847 sigemptyset(&(act.sa_mask));
00848 sigaddset(&(act.sa_mask), SIGPIPE);
00849 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
00850 act.sa_flags = 0;
00851 sigaction( SIGPIPE, &act, 0L);
00852 }
00853
00854 static void init_kdeinit_socket()
00855 {
00856 struct sockaddr_un sa;
00857
00858 kde_socklen_t socklen;
00859 long options;
00860 const QByteArray home_dir = qgetenv("HOME");
00861 int max_tries = 10;
00862 if (home_dir.isEmpty())
00863 {
00864 fprintf(stderr, "kdeinit4: Aborting. $HOME not set!");
00865 exit(255);
00866 }
00867 chdir(home_dir);
00868
00869 {
00870 QByteArray path = home_dir;
00871 QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00872 if (access(path.data(), R_OK|W_OK))
00873 {
00874 if (errno == ENOENT)
00875 {
00876 fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data());
00877 exit(255);
00878 }
00879 else if (readOnly.isEmpty())
00880 {
00881 fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data());
00882 exit(255);
00883 }
00884 }
00885 #if 0 // obsolete in kde4. Should we check writing to another file instead?
00886 path = qgetenv("ICEAUTHORITY");
00887 if (path.isEmpty())
00888 {
00889 path = home_dir;
00890 path += "/.ICEauthority";
00891 }
00892 if (access(path.data(), R_OK|W_OK) && (errno != ENOENT))
00893 {
00894 fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data());
00895 exit(255);
00896 }
00897 #endif
00898 }
00899
00904 if (access(sock_file, W_OK) == 0)
00905 {
00906 int s;
00907 struct sockaddr_un server;
00908
00909
00910
00911
00912
00913 s = socket(PF_UNIX, SOCK_STREAM, 0);
00914 if (s < 0)
00915 {
00916 perror("socket() failed: ");
00917 exit(255);
00918 }
00919 server.sun_family = AF_UNIX;
00920 strcpy(server.sun_path, sock_file);
00921 socklen = sizeof(server);
00922
00923 if(connect(s, (struct sockaddr *)&server, socklen) == 0)
00924 {
00925 fprintf(stderr, "kdeinit4: Shutting down running client.\n");
00926 klauncher_header request_header;
00927 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT;
00928 request_header.arg_length = 0;
00929 write(s, &request_header, sizeof(request_header));
00930 sleep(1);
00931 }
00932 close(s);
00933 }
00934
00936 unlink(sock_file);
00937
00938
00940 d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0);
00941 if (d.wrapper < 0)
00942 {
00943 perror("kdeinit4: Aborting. socket() failed: ");
00944 exit(255);
00945 }
00946
00947 options = fcntl(d.wrapper, F_GETFL);
00948 if (options == -1)
00949 {
00950 perror("kdeinit4: Aborting. Can not make socket non-blocking: ");
00951 close(d.wrapper);
00952 exit(255);
00953 }
00954
00955 if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1)
00956 {
00957 perror("kdeinit4: Aborting. Can not make socket non-blocking: ");
00958 close(d.wrapper);
00959 exit(255);
00960 }
00961
00962 if (fcntl(d.wrapper, F_SETFD, FD_CLOEXEC) == -1)
00963 {
00964 perror("kdeinit4: Aborting. Can not make socket close-on-execute: ");
00965 close(d.wrapper);
00966 exit(255);
00967 }
00968
00969 while (1) {
00971 socklen = sizeof(sa);
00972 memset(&sa, 0, socklen);
00973 sa.sun_family = AF_UNIX;
00974 strcpy(sa.sun_path, sock_file);
00975 if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0)
00976 {
00977 if (max_tries == 0) {
00978 perror("kdeinit4: Aborting. bind() failed: ");
00979 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file);
00980 close(d.wrapper);
00981 exit(255);
00982 }
00983 max_tries--;
00984 } else
00985 break;
00986 }
00987
00989 if (chmod(sock_file, 0600) != 0)
00990 {
00991 perror("kdeinit4: Aborting. Can not set permissions on socket: ");
00992 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
00993 unlink(sock_file);
00994 close(d.wrapper);
00995 exit(255);
00996 }
00997
00998 if(listen(d.wrapper, SOMAXCONN) < 0)
00999 {
01000 perror("kdeinit4: Aborting. listen() failed: ");
01001 unlink(sock_file);
01002 close(d.wrapper);
01003 exit(255);
01004 }
01005
01006 #if 0
01007
01008 d.wrapper_old = socket(PF_UNIX, SOCK_STREAM, 0);
01009 if (d.wrapper_old < 0)
01010 {
01011
01012 return;
01013 }
01014
01015 options = fcntl(d.wrapper_old, F_GETFL);
01016 if (options == -1)
01017 {
01018
01019 close(d.wrapper_old);
01020 d.wrapper_old = -1;
01021 return;
01022 }
01023
01024 if (fcntl(d.wrapper_old, F_SETFL, options | O_NONBLOCK) == -1)
01025 {
01026
01027 close(d.wrapper_old);
01028 d.wrapper_old = -1;
01029 return;
01030 }
01031
01032 if (fcntl(d.wrapper, F_SETFD, FD_CLOEXEC) == -1)
01033 {
01034
01035 close(d.wrapper);
01036 d.wrapper_old = -1;
01037 return;
01038 }
01039
01040 max_tries = 10;
01041 while (1) {
01043 socklen = sizeof(sa_old);
01044 memset(&sa_old, 0, socklen);
01045 sa_old.sun_family = AF_UNIX;
01046 strcpy(sa_old.sun_path, sock_file_old);
01047 if(bind(d.wrapper_old, (struct sockaddr *)&sa_old, socklen) != 0)
01048 {
01049 if (max_tries == 0) {
01050
01051 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file_old);
01052 close(d.wrapper_old);
01053 d.wrapper_old = -1;
01054 return;
01055 }
01056 max_tries--;
01057 } else
01058 break;
01059 }
01060
01062 if (chmod(sock_file_old, 0600) != 0)
01063 {
01064 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
01065 unlink(sock_file_old);
01066 close(d.wrapper_old);
01067 d.wrapper_old = -1;
01068 return;
01069 }
01070
01071 if(listen(d.wrapper_old, SOMAXCONN) < 0)
01072 {
01073
01074 unlink(sock_file_old);
01075 close(d.wrapper_old);
01076 d.wrapper_old = -1;
01077 }
01078 #endif
01079 }
01080
01081
01082
01083
01084
01085 static int read_socket(int sock, char *buffer, int len)
01086 {
01087 ssize_t result;
01088 int bytes_left = len;
01089 while ( bytes_left > 0)
01090 {
01091 result = read(sock, buffer, bytes_left);
01092 if (result > 0)
01093 {
01094 buffer += result;
01095 bytes_left -= result;
01096 }
01097 else if (result == 0)
01098