• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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 
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>     // Needed on some systems.
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 // #define SKIP_PROCTITLE 1
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 /* Group data */
00121 static struct {
00122   int maxname;
00123   int fd[2];
00124   int launcher[2]; /* socket pair for launcher communication */
00125   int deadpipe[2]; /* pipe used to detect dead children */
00126   int initpipe[2];
00127   int wrapper; /* socket for wrapper communication */
00128   int accepted_fd; /* socket accepted and that must be closed in the child process */
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; /* fd to write message when child is dead*/
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 /* These are to link libkparts even if 'smart' linker is used */
00161 #include <kparts/plugin.h>
00162 extern "C" KParts::Plugin* _kinit_init_kparts() { return new KParts::Plugin(); }
00163 /* These are to link libkio even if 'smart' linker is used */
00164 #include <kio/authinfo.h>
00165 extern "C" KIO::AuthInfo* _kioslave_init_kio() { return new KIO::AuthInfo(); }
00166 
00167 /*
00168  * Clean up the file descriptor table by closing all file descriptors
00169  * that are still open.
00170  *
00171  * This function is called very early in the main() function, so that
00172  * we don't leak anything that was leaked to us.
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  * Close fd's which are only useful for the parent process.
00186  * Restore default signal handlers.
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 /* Notify wrapper program that the child it started has finished. */
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          /* Send a message with the return value of the child on the control socket */
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; // Error with msg
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 // from kdecore/netwm.cpp
00317 static int get_current_desktop( Display* disp )
00318 {
00319     int desktop = 0; // no desktop by default
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 // var has to be e.g. "DISPLAY=", i.e. with =
00340 const char* get_env_var( const char* var, int envc, const char* envs )
00341 {
00342     if( envc > 0 )
00343     { // get the var from envs
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     // this may be called in a child, so it can't use display open using X11display
00363     // also needed for multihead
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 ) // failure
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 ) /* use the passed environment */
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             // try to match an absolute path to an executable binary (either in bin/ or in libexec/)
00454             // to a kdeinit module in the same prefix
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             // Don't confuse the user with "Could not load libkdeinit4_foo.so" if it doesn't exist
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      // Try to chdir, either to the requested directory or to the user's document path by default.
00511      // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist,
00512      // we still want to execute `foo` even if the chdir() failed.
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 ) // KWRAPPER/SHELL
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        /* set the process name, so that killall works like intended */
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              // Error
00607              QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError);
00608              exitWithErrorMsg(errorMsg);
00609           }
00610           else
00611           {
00612              // Print warning
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; // Try execing
00621         write(d.fd[1], &d.result, 1);
00622 
00623         // We set the close on exec flag.
00624         // Closing of d.fd[1] indicates that the execvp succeeded!
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; // Error
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; // Success
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)); /* Launch! */
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              //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n");
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           // Finished
00713           break;
00714        }
00715        if (d.n == -1)
00716        {
00717           if (errno == ECHILD) {  // a child died.
00718              continue;
00719           }
00720           if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read
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; // Error
00732           }
00733           break;
00734        }
00735        perror("kdeinit4: Error reading from pipe");
00736        d.result = 1; // Error
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 ) // launched successfully
00745         complete_startup_info( startup_id, d.fork );
00746      else // failure, cancel ASN
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     * Write into the pipe of death.
00759     * This way we are sure that we return from the select()
00760     *
00761     * A signal itself causes select to return as well, but
00762     * this creates a race-condition in case the signal arrives
00763     * just before we enter the select.
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    * A SIGCHLD handler is installed which sends a byte into the
00797    * pipe of death. This is to ensure that a dying child causes
00798    * an exit from select().
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   // CC: take care of SunOS which automatically restarts interrupted system
00807   // calls (and thus does not have SA_RESTART)
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 //     fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n");
00880      /*
00881       * create the socket stream
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); // Give it some time
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  * Read 'len' bytes from 'sock' into buffer.
00971  * returns 0 on success, -1 on failure.
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       /* This is bad. */
01015       fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
01016       ::exit(255);
01017       return;
01018    }
01019 
01020    // KLauncher died... restart
01021 #ifndef NDEBUG
01022    fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
01023 #endif
01024    // Make sure it's really dead.
01025    if (d.launcher_pid)
01026    {
01027       kill(d.launcher_pid, SIGKILL);
01028       sleep(1); // Give it some time
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; // for NDEBUG
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    //kDebug() << "Got cmd" << request_header.cmd << commandToString(request_header.cmd);
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          // Shell or kwrapper
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          // Optional cwd
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; // sure?
01155      }
01156 
01157       // support for the old a bit broken way of setting DISPLAY for multihead
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          /* add new child to list */
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++; // Include trailing null.
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; // sure?
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       /* Flush the pipe of death */
01292       while( read(d.deadpipe[0], &c, 1) == 1)
01293         {}
01294 
01295       /* Handle dying children */
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 )) // fix process return value
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       /* Handle wrapper request */
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       /* Handle launcher request */
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       /* Look for incoming X11 events */
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 //   if (!extra_path.isEmpty())
01426 //      lt_dlsetsearchpath(extra_path.data());
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    // WARNING, if you change the socket name, adjust kwrapper too
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     // disp is 0L when KDE shuts down. We don't want those warnings then.
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     // Don't kill our children in suicide mode, they may still be in use
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     /* this should remove all children we started */
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     /* and if they don't listen to us, this should work */
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     // kdeinit almost doesn't use X, and therefore there shouldn't be any X error
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     //kDebug() << kBacktrace();
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 // needs to be done sooner than initXconnection() because of also opening
01527 // another X connection for startup notification purposes
01528 static void setupX()
01529 {
01530     XSetIOErrorHandler(kdeinit_xio_errhandler);
01531     XSetErrorHandler(kdeinit_x_errhandler);
01532 }
01533 
01534 // Borrowed from kdebase/kaudio/kaudioserver.cpp
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       // make it nofork to match KUniqueApplication, technically command-line incompatible
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      // printf("    --no-dcop         Do not start dcopserver\n");
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      // printf("    --no-klauncher    Do not start klauncher\n");
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      // printf("    --exit            Terminate when kded has run\n");
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       // Fork here and let parent process exit.
01635       // Parent process may only exit after all required services have been
01636       // launched. (dcopserver/klauncher and services which start with '+')
01637       KDE_signal( SIGCHLD, secondary_child_handler);
01638       if (fork() > 0) // Go into background
01639       {
01640          close(d.initpipe[1]);
01641          d.initpipe[1] = -1;
01642          // wait till init is complete
01643          char c;
01644          while( read(d.initpipe[0], &c, 1) < 0)
01645             ;
01646          // then exit;
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    // Don't make our instance the global instance
01670    // (do it only after kdeinit_library_path, that one indirectly uses KConfig,
01671    // which seems to be buggy and always use KGlobal instead of the matching KComponentData)
01672    Q_ASSERT(!KGlobal::hasMainComponent());
01673    // don't change envvars before proctitle_init()
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        * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper
01695        * requests.
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        // can't use KLibLoader here as it would unload the library
01708        // again
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); // Wait for klauncher to be ready
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          // Similar to QApplication::create_xim()
01732      // but we need to use our own display
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          // Ignore
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); // Kdeinit is started.
01789       close(d.initpipe[1]);
01790       d.initpipe[1] = -1;
01791    }
01792 
01793    handle_requests(0);
01794 
01795    return 0;
01796 }
01797 
01798 

KInit

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal