• Skip to content
  • Skip to link menu
KDE 4.1 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         return -1;
01099      else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
01100         return -1;
01101   }
01102   return 0;
01103 }
01104 
01105 static void launcher_died()
01106 {
01107    if (!d.launcher_ok)
01108    {
01109       /* This is bad. */
01110       fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
01111       ::exit(255);
01112       return;
01113    }
01114 
01115    // KLauncher died... restart
01116 #ifndef NDEBUG
01117    fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
01118 #endif
01119    // Make sure it's really dead.
01120    if (d.launcher_pid)
01121    {
01122       kill(d.launcher_pid, SIGKILL);
01123       sleep(1); // Give it some time
01124    }
01125 
01126    d.launcher_ok = false;
01127    d.launcher_pid = 0;
01128    close(d.launcher[0]);
01129    d.launcher[0] = -1;
01130 
01131    pid_t pid = launch( 1, "klauncher", 0 );
01132 #ifndef NDEBUG
01133    fprintf(stderr, "kdeinit4: Relaunching KLauncher, pid = %ld result = %d\n", (long) pid, d.result);
01134 #endif
01135 }
01136 
01137 static void handle_launcher_request(int sock = -1)
01138 {
01139    bool launcher = false;
01140    if (sock < 0)
01141    {
01142        sock = d.launcher[0];
01143        launcher = true;
01144    }
01145    else
01146    {
01147        d.accepted_fd = sock;
01148    }
01149 
01150    klauncher_header request_header;
01151    char *request_data = 0L;
01152    int result = read_socket(sock, (char *) &request_header, sizeof(request_header));
01153    if (result != 0)
01154    {
01155       if (launcher)
01156          launcher_died();
01157       return;
01158    }
01159 
01160    if ( request_header.arg_length != 0 )
01161    {
01162        request_data = (char *) malloc(request_header.arg_length);
01163 
01164        result = read_socket(sock, request_data, request_header.arg_length);
01165        if (result != 0)
01166        {
01167            if (launcher)
01168                launcher_died();
01169            free(request_data);
01170            return;
01171        }
01172    }
01173 
01174    if (request_header.cmd == LAUNCHER_OK)
01175    {
01176       d.launcher_ok = true;
01177    }
01178    else if (request_header.arg_length &&
01179       ((request_header.cmd == LAUNCHER_EXEC) ||
01180        (request_header.cmd == LAUNCHER_EXT_EXEC) ||
01181        (request_header.cmd == LAUNCHER_SHELL ) ||
01182        (request_header.cmd == LAUNCHER_KWRAPPER) ||
01183        (request_header.cmd == LAUNCHER_EXEC_NEW)))
01184    {
01185       pid_t pid;
01186       klauncher_header response_header;
01187       long response_data;
01188       long l;
01189       memcpy( &l, request_data, sizeof( long ));
01190       int argc = l;
01191       const char *name = request_data + sizeof(long);
01192       const char *args = name + strlen(name) + 1;
01193       const char *cwd = 0;
01194       int envc = 0;
01195       const char *envs = 0;
01196       const char *tty = 0;
01197       int avoid_loops = 0;
01198       const char *startup_id_str = "0";
01199 
01200 #ifndef NDEBUG
01201      fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n",
01202         (request_header.cmd == LAUNCHER_EXEC ? "EXEC" :
01203         (request_header.cmd == LAUNCHER_EXT_EXEC ? "EXT_EXEC" :
01204         (request_header.cmd == LAUNCHER_EXEC_NEW ? "EXEC_NEW" :
01205         (request_header.cmd == LAUNCHER_SHELL ? "SHELL" : "KWRAPPER" )))),
01206          name, launcher ? "launcher" : "socket" );
01207 #endif
01208 
01209       const char *arg_n = args;
01210       for(int i = 1; i < argc; i++)
01211       {
01212         arg_n = arg_n + strlen(arg_n) + 1;
01213       }
01214 
01215       if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER )
01216       {
01217          // Shell or kwrapper
01218          cwd = arg_n; arg_n += strlen(cwd) + 1;
01219       }
01220       if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01221           || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01222       {
01223          memcpy( &l, arg_n, sizeof( long ));
01224          envc = l;
01225          arg_n += sizeof(long);
01226          envs = arg_n;
01227          for(int i = 0; i < envc; i++)
01228          {
01229            arg_n = arg_n + strlen(arg_n) + 1;
01230          }
01231          if( request_header.cmd == LAUNCHER_KWRAPPER )
01232          {
01233              tty = arg_n;
01234              arg_n += strlen( tty ) + 1;
01235          }
01236       }
01237 
01238      if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01239          || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
01240      {
01241          memcpy( &l, arg_n, sizeof( long ));
01242          avoid_loops = l;
01243          arg_n += sizeof( long );
01244      }
01245 
01246      if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
01247          || request_header.cmd == LAUNCHER_EXT_EXEC )
01248      {
01249          startup_id_str = arg_n;
01250          arg_n += strlen( startup_id_str ) + 1;
01251      }
01252 
01253      if ((request_header.arg_length > (arg_n - request_data)) &&
01254          (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ))
01255      {
01256          // Optional cwd
01257          cwd = arg_n; arg_n += strlen(cwd) + 1;
01258      }
01259 
01260      if ((arg_n - request_data) != request_header.arg_length)
01261      {
01262 #ifndef NDEBUG
01263        fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n");
01264 #endif
01265        free(request_data);
01266        d.debug_wait = false;
01267        return;
01268      }
01269 
01270       // support for the old a bit broken way of setting DISPLAY for multihead
01271       QByteArray olddisplay = qgetenv(DISPLAY);
01272       QByteArray kdedisplay = qgetenv("KDE_DISPLAY");
01273       bool reset_display = (! olddisplay.isEmpty() &&
01274                             ! kdedisplay.isEmpty() &&
01275                             olddisplay != kdedisplay);
01276 
01277       if (reset_display)
01278           setenv(DISPLAY, kdedisplay, true);
01279 
01280       pid = launch( argc, name, args, cwd, envc, envs,
01281           request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER,
01282           tty, avoid_loops, startup_id_str );
01283 
01284       if (reset_display) {
01285           unsetenv("KDE_DISPLAY");
01286           setenv(DISPLAY, olddisplay, true);
01287       }
01288 
01289       if (pid && (d.result == 0))
01290       {
01291          response_header.cmd = LAUNCHER_OK;
01292          response_header.arg_length = sizeof(response_data);
01293          response_data = pid;
01294          write(sock, &response_header, sizeof(response_header));
01295          write(sock, &response_data, response_header.arg_length);
01296 
01297          /* add new child to list */
01298          struct child *child = (struct child *) malloc(sizeof(struct child));
01299          child->pid = pid;
01300          child->sock = dup(sock);
01301          child->next = children;
01302          children = child;
01303 
01304          /* check child hasn't terminated already */
01305          if (kill(pid, 0))
01306          {
01307             children = child->next;
01308             free(child);
01309          }
01310       }
01311       else
01312       {
01313          int l = d.errorMsg.length();
01314          if (l) l++; // Include trailing null.
01315          response_header.cmd = LAUNCHER_ERROR;
01316          response_header.arg_length = l;
01317          write(sock, &response_header, sizeof(response_header));
01318          if (l)
01319             write(sock, d.errorMsg.data(), l);
01320       }
01321       d.debug_wait = false;
01322    }
01323    else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV)
01324    {
01325       const char *env_name;
01326       const char *env_value;
01327       env_name = request_data;
01328       env_value = env_name + strlen(env_name) + 1;
01329 
01330 #ifndef NDEBUG
01331       if (launcher)
01332          fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from klauncher.\n", env_name, env_value);
01333       else
01334          fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from socket.\n", env_name, env_value);
01335 #endif
01336 
01337       if ( request_header.arg_length !=
01338           (int) (strlen(env_name) + strlen(env_value) + 2))
01339       {
01340 #ifndef NDEBUG
01341          fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n");
01342 #endif
01343          free(request_data);
01344          return;
01345       }
01346       setenv( env_name, env_value, 1);
01347    }
01348    else if (request_header.cmd == LAUNCHER_TERMINATE_KDE)
01349    {
01350 #ifndef NDEBUG
01351        fprintf(stderr,"kdeinit4: terminate KDE.\n");
01352 #endif
01353 #ifdef Q_WS_X11
01354        kdeinit_xio_errhandler( 0L );
01355 #endif
01356    }
01357    else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT)
01358    {
01359 #ifndef NDEBUG
01360        fprintf(stderr,"kdeinit4: Killing kdeinit/klauncher.\n");
01361 #endif
01362        if (d.launcher_pid)
01363           kill(d.launcher_pid, SIGTERM);
01364        if (d.my_pid)
01365           kill(d.my_pid, SIGTERM);
01366    }
01367    else if (request_header.cmd == LAUNCHER_DEBUG_WAIT)
01368    {
01369 #ifndef NDEBUG
01370        fprintf(stderr,"kdeinit4: Debug wait activated.\n");
01371 #endif
01372        d.debug_wait = true;
01373    }
01374    if (request_data)
01375        free(request_data);
01376 }
01377 
01378 static void handle_requests(pid_t waitForPid)
01379 {
01380    int max_sock = d.wrapper;
01381    if (d.wrapper_old > max_sock)
01382       max_sock = d.wrapper_old;
01383    if (d.launcher_pid && (d.launcher[0] > max_sock))
01384       max_sock = d.launcher[0];
01385 #ifdef Q_WS_X11
01386    if (X11fd > max_sock)
01387       max_sock = X11fd;
01388 #endif
01389    max_sock++;
01390 
01391    while(1)
01392    {
01393       fd_set rd_set;
01394       fd_set wr_set;
01395       fd_set e_set;
01396       int result;
01397       pid_t exit_pid;
01398       int exit_status;
01399       char c;
01400 
01401       /* Flush the pipe of death */
01402       while( read(d.deadpipe[0], &c, 1) == 1);
01403 
01404       /* Handle dying children */
01405       do {
01406         exit_pid = waitpid(-1, &exit_status, WNOHANG);
01407         if (exit_pid > 0)
01408         {
01409 #ifndef NDEBUG
01410            fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid);
01411 #endif
01412            if (waitForPid && (exit_pid == waitForPid))
01413               return;
01414 
01415            if( WIFEXITED( exit_status )) // fix process return value
01416                exit_status = WEXITSTATUS(exit_status);
01417            else if( WIFSIGNALED( exit_status ))
01418                exit_status = 128 + WTERMSIG( exit_status );
01419            child_died(exit_pid, exit_status);
01420         }
01421       }
01422       while( exit_pid > 0);
01423 
01424       /* Set up the next loop */
01425       d.accepted_fd = -1;
01426 
01427       FD_ZERO(&rd_set);
01428       FD_ZERO(&wr_set);
01429       FD_ZERO(&e_set);
01430 
01431       if (d.launcher_pid)
01432       {
01433          FD_SET(d.launcher[0], &rd_set);
01434       }
01435       FD_SET(d.wrapper, &rd_set);
01436       if (d.wrapper_old != -1)
01437       {
01438          FD_SET(d.wrapper_old, &rd_set);
01439       }
01440       FD_SET(d.deadpipe[0], &rd_set);
01441 #ifdef Q_WS_X11
01442       if(X11fd >= 0) FD_SET(X11fd, &rd_set);
01443 #endif
01444 
01445       result = select(max_sock, &rd_set, &wr_set, &e_set, 0);
01446 
01447       /* Handle wrapper request */
01448       if ((result > 0) && (FD_ISSET(d.wrapper, &rd_set)))
01449       {
01450          struct sockaddr_un client;
01451          kde_socklen_t sClient = sizeof(client);
01452          int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient);
01453          if (sock >= 0)
01454          {
01455             handle_launcher_request(sock);
01456             close(sock);
01457          }
01458       }
01459       if ((result > 0) && d.wrapper_old != -1 && (FD_ISSET(d.wrapper_old, &rd_set)))
01460       {
01461          struct sockaddr_un client;
01462          kde_socklen_t sClient = sizeof(client);
01463          int sock = accept(d.wrapper_old, (struct sockaddr *)&client, &sClient);
01464          if (sock >= 0)
01465          {
01466             handle_launcher_request(sock);
01467             close(sock);
01468          }
01469       }
01470 
01471       /* Handle launcher request */
01472       if ((result > 0) && (d.launcher_pid) && (FD_ISSET(d.launcher[0], &rd_set)))
01473       {
01474          handle_launcher_request();
01475          if (waitForPid == d.launcher_pid)
01476             return;
01477       }
01478 
01479 #ifdef Q_WS_X11
01480       /* Look for incoming X11 events */
01481       if((result > 0) && (X11fd >= 0))
01482       {
01483         if(FD_ISSET(X11fd,&rd_set))
01484         {
01485           if (X11display != 0) {
01486         XEvent event_return;
01487         while (XPending(X11display))
01488           XNextEvent(X11display, &event_return);
01489       }
01490         }
01491       }
01492 #endif
01493    }
01494 }
01495 
01496 static void kdeinit_library_path()
01497 {
01498    QStringList ltdl_library_path =
01499      QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(':',QString::SkipEmptyParts);
01500 #ifdef Q_OS_DARWIN
01501    QStringList ld_library_path =
01502      QFile::decodeName(qgetenv("DYLD_LIBRARY_PATH")).split(':',QString::SkipEmptyParts);
01503 #else
01504    QStringList ld_library_path =
01505      QFile::decodeName(qgetenv("LD_LIBRARY_PATH")).split(':',QString::SkipEmptyParts);
01506 #endif
01507 
01508    QByteArray extra_path;
01509    QStringList candidates = s_instance->dirs()->resourceDirs("lib");
01510    for (QStringList::ConstIterator it = candidates.begin();
01511         it != candidates.end();
01512         ++it)
01513    {
01514       QString d = *it;
01515       if (ltdl_library_path.contains(d))
01516           continue;
01517       if (ld_library_path.contains(d))
01518           continue;
01519       if (d[d.length()-1] == '/')
01520       {
01521          d.truncate(d.length()-1);
01522          if (ltdl_library_path.contains(d))
01523             continue;
01524          if (ld_library_path.contains(d))
01525             continue;
01526       }
01527       if ((d == "/lib") || (d == "/usr/lib"))
01528          continue;
01529 
01530       QByteArray dir = QFile::encodeName(d);
01531 
01532       if (access(dir, R_OK))
01533           continue;
01534 
01535       if ( !extra_path.isEmpty())
01536          extra_path += ':';
01537       extra_path += dir;
01538    }
01539 
01540 //   if (!extra_path.isEmpty())
01541 //      lt_dlsetsearchpath(extra_path.data());
01542 
01543    QByteArray display = qgetenv(DISPLAY);
01544    if (display.isEmpty())
01545    {
01546 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
01547      fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n");
01548      exit(255);
01549 #endif
01550    }
01551    int i;
01552    if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
01553      display.truncate(i);
01554 
01555    // Was kdeinit-display initially,
01556    // then at some point in KDE-3.x it became kdeinit_display_with_underscores
01557    // And for KDE4 it became kdeinit4_display_with_underscores, to avoid messing up the kde3 kdeinit.
01558    // Compat code needed just in case we need it later for something else.
01559 #if 0
01560    QByteArray socketName = QFile::encodeName(locateLocal("socket", QString("kdeinit-%1").arg(QLatin1String(display)), *s_instance));
01561    if (socketName.length() >= MAX_SOCK_FILE)
01562    {
01563      fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
01564      fprintf(stderr, "         '%s'\n", socketName.data());
01565      exit(255);
01566    }
01567    strcpy(sock_file_old, socketName.data());
01568 #endif
01569 
01570    display.replace(':','_');
01571    // WARNING, if you change the socket name, adjust kwrapper too
01572    QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", QString("kdeinit4_%1").arg(QLatin1String(display)), *s_instance));
01573    if (socketName.length() >= MAX_SOCK_FILE)
01574    {
01575      fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
01576      fprintf(stderr, "         '%s'\n", socketName.data());
01577      exit(255);
01578    }
01579    strcpy(sock_file, socketName.data());
01580 }
01581 
01582 int kdeinit_xio_errhandler( Display *disp )
01583 {
01584     // disp is 0L when KDE shuts down. We don't want those warnings then.
01585 
01586     if ( disp )
01587     qWarning( "kdeinit4: Fatal IO error: client killed" );
01588 
01589     if (sock_file[0])
01590     {
01592       unlink(sock_file);
01593     }
01594 #if 0
01595     if (sock_file_old[0])
01596     {
01598       unlink(sock_file_old);
01599     }
01600 #endif
01601 
01602     // Don't kill our children in suicide mode, they may still be in use
01603     if (d.suicide)
01604     {
01605        if (d.launcher_pid)
01606           kill(d.launcher_pid, SIGTERM);
01607        if (d.kded_pid)
01608           kill(d.kded_pid, SIGTERM);
01609        exit( 0 );
01610     }
01611 
01612     if ( disp )
01613     qWarning( "kdeinit4: sending SIGHUP to children." );
01614 
01615     /* this should remove all children we started */
01616     KDE_signal(SIGHUP, SIG_IGN);
01617     kill(0, SIGHUP);
01618 
01619     sleep(2);
01620 
01621     if ( disp )
01622     qWarning( "kdeinit4: sending SIGTERM to children." );
01623 
01624     /* and if they don't listen to us, this should work */
01625     KDE_signal(SIGTERM, SIG_IGN);
01626     kill(0, SIGTERM);
01627 
01628     if ( disp )
01629     qWarning( "kdeinit4: Exit." );
01630 
01631     exit( 0 );
01632     return 0;
01633 }
01634 
01635 #ifdef Q_WS_X11
01636 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err )
01637 {
01638 #ifndef NDEBUG
01639     char errstr[256];
01640     // kdeinit almost doesn't use X, and therefore there shouldn't be any X error
01641     XGetErrorText( dpy, err->error_code, errstr, 256 );
01642     fprintf(stderr, "kdeinit4: KDE detected X Error: %s %d\n"
01643                     "         Major opcode: %d\n"
01644                     "         Minor opcode: %d\n"
01645                     "         Resource id:  0x%lx\n",
01646             errstr, err->error_code, err->request_code, err->minor_code, err->resourceid );
01647 #else
01648     Q_UNUSED(dpy);
01649     Q_UNUSED(err);
01650 #endif
01651     return 0;
01652 }
01653 #endif
01654 
01655 #ifdef Q_WS_X11
01656 // needs to be done sooner than initXconnection() because of also opening
01657 // another X connection for startup notification purposes
01658 static void setupX()
01659 {
01660     XSetIOErrorHandler(kdeinit_xio_errhandler);
01661     XSetErrorHandler(kdeinit_x_errhandler);
01662 }
01663 
01664 // Borrowed from kdebase/kaudio/kaudioserver.cpp
01665 static int initXconnection()
01666 {
01667   X11display = XOpenDisplay(NULL);
01668   if ( X11display != 0 ) {
01669     XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \
01670         0,
01671         BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)),
01672         BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) );
01673 #ifndef NDEBUG
01674     fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display));
01675 #endif
01676     int fd = XConnectionNumber( X11display );
01677     int on = 1;
01678     (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on));
01679     return fd;
01680   } else
01681     fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \
01682      "kdeinit4: Might not terminate at end of session.\n");
01683 
01684   return -1;
01685 }
01686 #endif
01687 
01688 #ifdef __KCC
01689 /* One of my horrible hacks.  KCC includes in each "main" function a call
01690    to _main(), which is provided by the C++ runtime system.  It is
01691    responsible for calling constructors for some static objects.  That must
01692    be done only once, so _main() is guarded against multiple calls.
01693    For unknown reasons the designers of KAI's libKCC decided it would be
01694    a good idea to actually abort() when it's called multiple times, instead
01695    of ignoring further calls.  This breaks our mechanism of KLM's, because
01696    most KLM's have a main() function which is called from us.
01697    The "solution" is to simply define our own _main(), which ignores multiple
01698    calls, which is easy, and which does the same work as KAI'c _main(),
01699    which is difficult.  Currently (KAI 4.0f) it only calls __call_ctors(void)
01700    (a C++ function), but if that changes we need to change our's too.
01701    (matz) */
01702 /*
01703  Those 'unknown reasons' are C++ standard forbidding recursive calls to main()
01704  or any means that would possibly allow that (e.g. taking address of main()).
01705  The correct solution is not using main() as entry point for kdeinit modules,
01706  but only kdemain().
01707 */
01708 extern "C" void _main(void);
01709 extern "C" void __call_ctors__Fv(void);
01710 static int main_called = 0;
01711 void _main(void)
01712 {
01713   if (main_called)
01714     return;
01715   main_called = 1;
01716   __call_ctors__Fv ();
01717 }
01718 #endif
01719 
01720 static void secondary_child_handler(int)
01721 {
01722    waitpid(-1, 0, WNOHANG);
01723 }
01724 
01725 int main(int argc, char **argv, char **envp)
01726 {
01727    int i;
01728    pid_t pid;
01729    bool do_fork = true;
01730    int launch_klauncher = 1;
01731    int launch_kded = 1;
01732    int keep_running = 1;
01733    d.suicide = false;
01734 
01736    char **safe_argv = (char **) malloc( sizeof(char *) * argc);
01737    for(i = 0; i < argc; i++)
01738    {
01739       safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
01740       if (strcmp(safe_argv[i], "--no-klauncher") == 0)
01741          launch_klauncher = 0;
01742       if (strcmp(safe_argv[i], "--no-kded") == 0)
01743          launch_kded = 0;
01744 #ifdef Q_WS_MACX
01745       // make it nofork to match KUniqueApplication, technically command-line incompatible
01746       if (strcmp(safe_argv[i], "--nofork") == 0)
01747 #else
01748       if (strcmp(safe_argv[i], "--no-fork") == 0)
01749 #endif
01750          do_fork = false;
01751       if (strcmp(safe_argv[i], "--suicide") == 0)
01752          d.suicide = true;
01753       if (strcmp(safe_argv[i], "--exit") == 0)
01754          keep_running = 0;
01755       if (strcmp(safe_argv[i], "--help") == 0)
01756       {
01757         printf("Usage: kdeinit4 [options]\n");
01758      // printf("    --no-dcop         Do not start dcopserver\n");
01759 #ifdef Q_WS_MACX
01760         printf("    --nofork          Do not fork\n");
01761 #else
01762         printf("    --no-fork         Do not fork\n");
01763 #endif
01764      // printf("    --no-klauncher    Do not start klauncher\n");
01765         printf("    --no-kded         Do not start kded\n");
01766         printf("    --suicide         Terminate when no KDE applications are left running\n");
01767      // printf("    --exit            Terminate when kded has run\n");
01768         exit(0);
01769       }
01770    }
01771 
01772    cleanup_fds();
01773 
01774    if (do_fork) {
01775 #ifdef Q_WS_MACX
01776       mac_fork_and_reexec_self();
01777 #else
01778       pipe(d.initpipe);
01779 
01780       // Fork here and let parent process exit.
01781       // Parent process may only exit after all required services have been
01782       // launched. (dcopserver/klauncher and services which start with '+')
01783       KDE_signal( SIGCHLD, secondary_child_handler);
01784       if (fork() > 0) // Go into background
01785       {
01786          close(d.initpipe[1]);
01787          d.initpipe[1] = -1;
01788          // wait till init is complete
01789          char c;
01790          while( read(d.initpipe[0], &c, 1) < 0)
01791             ;
01792          // then exit;
01793          close(d.initpipe[0]);
01794          d.initpipe[0] = -1;
01795          return 0;
01796       }
01797       close(d.initpipe[0]);
01798       d.initpipe[0] = -1;
01799 #endif
01800    }
01801 
01804    if (d.initpipe[1] != -1)
01805       fcntl(d.initpipe[1], F_SETFD, FD_CLOEXEC);
01806 
01807    d.my_pid = getpid();
01808 
01810    if(keep_running)
01811       setsid();
01812 
01814    s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
01815 
01817    proctitle_init(argc, argv, envp);
01818    kdeinit_library_path();
01819    // Don't make our instance the global instance
01820    // (do it only after kdeinit_library_path, that one indirectly uses KConfig,
01821    // which seems to be buggy and always use KGlobal instead of the matching KComponentData)
01822    Q_ASSERT(!KGlobal::hasMainComponent());
01823    // don't change envvars before proctitle_init()
01824    unsetenv("LD_BIND_NOW");
01825    unsetenv("DYLD_BIND_AT_LAUNCH");
01826    KApplication::loadedByKdeinit = true;
01827 
01828    d.maxname = strlen(argv[0]);
01829    d.launcher_pid = 0;
01830    d.kded_pid = 0;
01831    d.wrapper = -1;
01832    d.wrapper_old = -1;
01833    d.accepted_fd = -1;
01834    d.debug_wait = false;
01835    d.launcher_ok = false;
01836    children = NULL;
01837    init_signals();
01838 #ifdef Q_WS_X11
01839    setupX();
01840 #endif
01841 
01842    if (keep_running)
01843    {
01844       /*
01845        * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper
01846        * requests.
01847        */
01848       init_kdeinit_socket();
01849    }
01850 #ifdef Q_WS_X11
01851    if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty())
01852    {
01853        QString konq = KStandardDirs::locate("lib", "libkonq.so.5", *s_instance);
01854        // can't use KLibLoader here as it would unload the library
01855        // again
01856        if (!konq.isEmpty()) {
01857            QLibrary l(konq);
01858            l.setLoadHints(QLibrary::ExportExternalSymbolsHint);
01859            l.load();
01860        }
01861    }
01862 #endif
01863    if (launch_klauncher)
01864    {
01865       pid = launch( 1, "klauncher", 0 );
01866 #ifndef NDEBUG
01867       fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld result = %d\n", (long) pid, d.result);
01868 #endif
01869       handle_requests(pid); // Wait for klauncher to be ready
01870    }
01871 
01872 #ifdef Q_WS_X11
01873    X11fd = initXconnection();
01874 #endif
01875 
01876    {
01877       QFont::initialize();
01878       setlocale (LC_ALL, "");
01879       setlocale (LC_NUMERIC, "C");
01880 #ifdef Q_WS_X11
01881       if (XSupportsLocale ())
01882       {
01883          // Similar to QApplication::create_xim()
01884      // but we need to use our own display
01885      XOpenIM (X11display, 0, 0, 0);
01886       }
01887 #endif
01888    }
01889 
01890    if (launch_kded)
01891    {
01892       pid = launch( 1, KDED_EXENAME, 0 );
01893 #ifndef NDEBUG
01894       fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result);
01895 #endif
01896       d.kded_pid = pid;
01897       handle_requests(pid);
01898    }
01899 
01900    for(i = 1; i < argc; i++)
01901    {
01902       if (safe_argv[i][0] == '+')
01903       {
01904          pid = launch( 1, safe_argv[i]+1, 0);
01905 #ifndef NDEBUG
01906       fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result);
01907 #endif
01908          handle_requests(pid);
01909       }
01910       else if (safe_argv[i][0] == '-')
01911       {
01912          // Ignore
01913       }
01914       else
01915       {
01916          pid = launch( 1, safe_argv[i], 0 );
01917 #ifndef NDEBUG
01918       fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result);
01919 #endif
01920       }
01921    }
01922 
01924    for(i = 0; i < argc; i++)
01925    {
01926       free(safe_argv[i]);
01927    }
01928    free (safe_argv);
01929 
01930    proctitle_set("kdeinit4 Running...");
01931 
01932    if (!keep_running)
01933       return 0;
01934 
01935    if (d.initpipe[1] != -1)
01936    {
01937       char c = 0;
01938       write(d.initpipe[1], &c, 1); // Kdeinit is started.
01939       close(d.initpipe[1]);
01940       d.initpipe[1] = -1;
01941    }
01942 
01943    handle_requests(0);
01944 
01945    return 0;
01946 }
01947 
01948 

KInit

Skip menu "KInit"
  • Main Page
  • Namespace List
  • 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
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
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