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

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