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