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