• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

KInit

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

KDE's Doxygen guidelines are available online.

KInit

Skip menu "KInit"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal