• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.5 API Reference
  • KDE Home
  • Contact Us
 

KInit

  • kinit
kinit.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 1999-2000 Waldo Bastian <bastian@kde.org>
4  * (c) 1999 Mario Weilguni <mweilguni@sime.com>
5  * (c) 2001 Lubos Lunak <l.lunak@kde.org>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License version 2 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 #define QT_NO_CAST_FROM_ASCII
23 
24 #include <config.h>
25 #include <config-kdeinit.h>
26 
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <sys/resource.h>
30 #include <sys/stat.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/wait.h>
34 #ifdef HAVE_SYS_SELECT_H
35 #include <sys/select.h> // Needed on some systems.
36 #endif
37 
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include "proctitle.h"
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <locale.h>
48 
49 #include <QtCore/QLibrary>
50 #include <QtCore/QString>
51 #include <QtCore/QFile>
52 #include <QtCore/QDate>
53 #include <QtCore/QFileInfo>
54 #include <QtCore/QRegExp>
55 #include <QtGui/QFont>
56 #include <kcomponentdata.h>
57 #include <klibrary.h>
58 #include <kdemacros.h>
59 #include <kstandarddirs.h>
60 #include <kglobalsettings.h>
61 #include <kglobal.h>
62 #include <kconfig.h>
63 #include <kapplication.h>
64 #include <klocale.h>
65 #include <kdebug.h>
66 #include <kde_file.h>
67 #include <ksavefile.h>
68 
69 #ifdef Q_OS_LINUX
70 #include <sys/prctl.h>
71 #ifndef PR_SET_NAME
72 #define PR_SET_NAME 15
73 #endif
74 #endif
75 
76 #ifdef Q_WS_MACX
77 #include <kkernel_mac.h>
78 #endif
79 
80 #include <kdeversion.h>
81 
82 #include "klauncher_cmds.h"
83 
84 #ifdef Q_WS_X11
85 #include <X11/Xlib.h>
86 #include <X11/Xatom.h>
87 #include <fixx11h.h>
88 #include <kstartupinfo.h>
89 #endif
90 
91 #ifdef Q_WS_X11
92 static const char *extra_libs[] = {
93  "libkio.so.5",
94  "libkparts.so.4",
95 #ifdef __KDE_HAVE_GCC_VISIBILITY
96  "libplasma.so.3"
97 #endif
98 };
99 #endif
100 
101 // #define SKIP_PROCTITLE 1
102 
103 extern char **environ;
104 
105 #ifdef Q_WS_X11
106 static int X11fd = -1;
107 static Display *X11display = 0;
108 static int X11_startup_notify_fd = -1;
109 static Display *X11_startup_notify_display = 0;
110 #endif
111 static KComponentData *s_instance = 0;
112 #define MAX_SOCK_FILE 255
113 static char sock_file[MAX_SOCK_FILE];
114 
115 #ifdef Q_WS_X11
116 #define DISPLAY "DISPLAY"
117 #elif defined(Q_WS_QWS)
118 #define DISPLAY "QWS_DISPLAY"
119 #elif defined(Q_WS_MACX)
120 #define DISPLAY "MAC_DISPLAY"
121 #elif defined(Q_WS_WIN)
122 #define DISPLAY "WIN_DISPLAY"
123 #else
124 #error Use QT/X11 or QT/Embedded
125 #endif
126 
127 /* Group data */
128 static struct {
129  int maxname;
130  int fd[2];
131  int launcher[2]; /* socket pair for launcher communication */
132  int deadpipe[2]; /* pipe used to detect dead children */
133  int initpipe[2];
134  int wrapper; /* socket for wrapper communication */
135  int accepted_fd; /* socket accepted and that must be closed in the child process */
136  char result;
137  int exit_status;
138  pid_t fork;
139  pid_t launcher_pid;
140  pid_t kded_pid;
141  int n;
142  char **argv;
143  int (*func)(int, char *[]);
144  int (*launcher_func)(int);
145  bool debug_wait;
146  QByteArray errorMsg;
147  bool launcher_ok;
148  bool suicide;
149 } d;
150 
151 struct child
152 {
153  pid_t pid;
154  int sock; /* fd to write message when child is dead*/
155  struct child *next;
156 };
157 
158 static struct child *children;
159 
160 #ifdef Q_WS_X11
161 extern "C" {
162 int kdeinit_xio_errhandler( Display * );
163 int kdeinit_x_errhandler( Display *, XErrorEvent *err );
164 }
165 #endif
166 
167 #ifdef KDEINIT_OOM_PROTECT
168 static int oom_pipe = -1;
169 #endif
170 
171 /*
172  * Clean up the file descriptor table by closing all file descriptors
173  * that are still open.
174  *
175  * This function is called very early in the main() function, so that
176  * we don't leak anything that was leaked to us.
177  */
178 static void cleanup_fds()
179 {
180  int maxfd = FD_SETSIZE;
181  struct rlimit rl;
182  if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
183  maxfd = rl.rlim_max;
184  for (int fd = 3; fd < maxfd; ++fd)
185  {
186 #ifdef KDEINIT_OOM_PROTECT
187  if( fd != oom_pipe )
188 #endif
189  close(fd);
190  }
191 }
192 
193 /*
194  * Close fd's which are only useful for the parent process.
195  * Restore default signal handlers.
196  */
197 static void close_fds()
198 {
199  while (struct child *child = children) {
200  close(child->sock);
201  children = child->next;
202  free(child);
203  }
204 
205  if (d.deadpipe[0] != -1)
206  {
207  close(d.deadpipe[0]);
208  d.deadpipe[0] = -1;
209  }
210 
211  if (d.deadpipe[1] != -1)
212  {
213  close(d.deadpipe[1]);
214  d.deadpipe[1] = -1;
215  }
216 
217  if (d.initpipe[0] != -1)
218  {
219  close(d.initpipe[0]);
220  d.initpipe[0] = -1;
221  }
222 
223  if (d.initpipe[1] != -1)
224  {
225  close(d.initpipe[1]);
226  d.initpipe[1] = -1;
227  }
228 
229  if (d.launcher[0] != -1)
230  {
231  close(d.launcher[0]);
232  d.launcher[0] = -1;
233  }
234  if (d.wrapper != -1)
235  {
236  close(d.wrapper);
237  d.wrapper = -1;
238  }
239  if (d.accepted_fd != -1)
240  {
241  close(d.accepted_fd);
242  d.accepted_fd = -1;
243  }
244 #ifdef Q_WS_X11
245  if (X11fd >= 0)
246  {
247  close(X11fd);
248  X11fd = -1;
249  }
250  if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd )
251  {
252  close(X11_startup_notify_fd);
253  X11_startup_notify_fd = -1;
254  }
255 #endif
256 
257  KDE_signal(SIGCHLD, SIG_DFL);
258  KDE_signal(SIGPIPE, SIG_DFL);
259 }
260 
261 /* Notify wrapper program that the child it started has finished. */
262 static void child_died(pid_t exit_pid, int exit_status)
263 {
264  struct child *child, **childptr = &children;
265 
266  while ((child = *childptr))
267  {
268  if (child->pid == exit_pid)
269  {
270  /* Send a message with the return value of the child on the control socket */
271  klauncher_header request_header;
272  long request_data[2];
273  request_header.cmd = LAUNCHER_CHILD_DIED;
274  request_header.arg_length = sizeof(long) * 2;
275  request_data[0] = exit_pid;
276  request_data[1] = exit_status;
277  write(child->sock, &request_header, sizeof(request_header));
278  write(child->sock, request_data, request_header.arg_length);
279  close(child->sock);
280 
281  *childptr = child->next;
282  free(child);
283  return;
284  }
285 
286  childptr = &child->next;
287  }
288 }
289 
290 
291 static void exitWithErrorMsg(const QString &errorMsg)
292 {
293  fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() );
294  QByteArray utf8ErrorMsg = errorMsg.toUtf8();
295  d.result = 3; // Error with msg
296  write(d.fd[1], &d.result, 1);
297  int l = utf8ErrorMsg.length();
298  write(d.fd[1], &l, sizeof(int));
299  write(d.fd[1], utf8ErrorMsg.data(), l);
300  close(d.fd[1]);
301  exit(255);
302 }
303 
304 static void setup_tty( const char* tty )
305 {
306  if( tty == NULL || *tty == '\0' )
307  return;
308  int fd = KDE_open( tty, O_WRONLY );
309  if( fd < 0 )
310  {
311  perror( "kdeinit4: could not open() tty" );
312  return;
313  }
314  if( dup2( fd, STDOUT_FILENO ) < 0 )
315  {
316  perror( "kdeinit4: could not dup2() stdout tty" );
317  }
318  if( dup2( fd, STDERR_FILENO ) < 0 )
319  {
320  perror( "kdeinit4: could not dup2() stderr tty" );
321  }
322  close( fd );
323 }
324 
325 // from kdecore/netwm.cpp
326 static int get_current_desktop( Display* disp )
327 {
328  int desktop = 0; // no desktop by default
329 #ifdef Q_WS_X11 // Only X11 supports multiple desktops
330  Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False );
331  Atom type_ret;
332  int format_ret;
333  unsigned char *data_ret;
334  unsigned long nitems_ret, unused;
335  if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop,
336  0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret )
337  == Success)
338  {
339  if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1)
340  desktop = *((long *) data_ret) + 1;
341  if (data_ret)
342  XFree ((char*) data_ret);
343  }
344 #endif
345  return desktop;
346 }
347 
348 // var has to be e.g. "DISPLAY=", i.e. with =
349 const char* get_env_var( const char* var, int envc, const char* envs )
350 {
351  if( envc > 0 )
352  { // get the var from envs
353  const char* env_l = envs;
354  int ln = strlen( var );
355  for (int i = 0; i < envc; i++)
356  {
357  if( strncmp( env_l, var, ln ) == 0 )
358  return env_l + ln;
359  while(*env_l != 0) env_l++;
360  env_l++;
361  }
362  }
363  return NULL;
364 }
365 
366 #ifdef Q_WS_X11
367 static void init_startup_info( KStartupInfoId& id, const char* bin,
368  int envc, const char* envs )
369 {
370  const char* dpy = get_env_var( DISPLAY"=", envc, envs );
371  // this may be called in a child, so it can't use display open using X11display
372  // also needed for multihead
373  X11_startup_notify_display = XOpenDisplay( dpy );
374  if( X11_startup_notify_display == NULL )
375  return;
376  X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display );
377  KStartupInfoData data;
378  int desktop = get_current_desktop( X11_startup_notify_display );
379  data.setDesktop( desktop );
380  data.setBin(QFile::decodeName(bin));
381  KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
382  XFlush( X11_startup_notify_display );
383 }
384 
385 static void complete_startup_info( KStartupInfoId& id, pid_t pid )
386 {
387  if( X11_startup_notify_display == NULL )
388  return;
389  if( pid == 0 ) // failure
390  KStartupInfo::sendFinishX( X11_startup_notify_display, id );
391  else
392  {
393  KStartupInfoData data;
394  data.addPid( pid );
395  data.setHostname();
396  KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
397  }
398  XCloseDisplay( X11_startup_notify_display );
399  X11_startup_notify_display = NULL;
400  X11_startup_notify_fd = -1;
401 }
402 #endif
403 
404 QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops )
405 {
406  QStringList paths;
407  const QRegExp pathSepRegExp(QString::fromLatin1("[:\b]"));
408  if( envc > 0 ) /* use the passed environment */
409  {
410  const char* path = get_env_var( "PATH=", envc, envs );
411  if( path != NULL )
412  paths = QFile::decodeName(path).split(pathSepRegExp);
413  } else {
414  paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSepRegExp, QString::KeepEmptyParts);
415  }
416  QString execpath =
417  s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":")));
418  if (avoid_loops && !execpath.isEmpty()) {
419  const int pos = execpath.lastIndexOf(QLatin1Char('/'));
420  const QString bin_path = execpath.left(pos);
421  for( QStringList::Iterator it = paths.begin();
422  it != paths.end();
423  ++it ) {
424  if( *it == bin_path || *it == bin_path + QLatin1Char('/')) {
425  paths.erase( it );
426  break; // -->
427  }
428  }
429  execpath = s_instance->dirs()->findExe(QFile::decodeName(exec), paths.join(QLatin1String(":")));
430  }
431  return QFile::encodeName(execpath);
432 }
433 
434 #ifdef KDEINIT_OOM_PROTECT
435 static void oom_protect_sighandler( int ) {
436 }
437 
438 static void reset_oom_protect() {
439  if( oom_pipe <= 0 )
440  return;
441  struct sigaction act, oldact;
442  act.sa_handler = oom_protect_sighandler;
443  act.sa_flags = 0;
444  sigemptyset( &act.sa_mask );
445  sigaction( SIGUSR1, &act, &oldact );
446  sigset_t sigs, oldsigs;
447  sigemptyset( &sigs );
448  sigaddset( &sigs, SIGUSR1 );
449  sigprocmask( SIG_BLOCK, &sigs, &oldsigs );
450  pid_t pid = getpid();
451  if( write( oom_pipe, &pid, sizeof( pid_t )) > 0 ) {
452  sigsuspend( &oldsigs ); // wait for the signal to come
453  } else {
454 #ifndef NDEBUG
455  fprintf( stderr, "Failed to reset OOM protection: %d\n", pid );
456 #endif
457  }
458  sigprocmask( SIG_SETMASK, &oldsigs, NULL );
459  sigaction( SIGUSR1, &oldact, NULL );
460  close( oom_pipe );
461  oom_pipe = -1;
462 }
463 #else
464 static void reset_oom_protect() {
465 }
466 #endif
467 
468 static pid_t launch(int argc, const char *_name, const char *args,
469  const char *cwd=0, int envc=0, const char *envs=0,
470  bool reset_env = false,
471  const char *tty=0, bool avoid_loops = false,
472  const char* startup_id_str = "0" ) // krazy:exclude=doublequote_chars
473 {
474  QString lib;
475  QByteArray name;
476  QByteArray exec;
477  QString libpath;
478  QByteArray execpath;
479 
480  if (_name[0] != '/') {
481  name = _name;
482  lib = QFile::decodeName(name);
483  exec = name;
484  KLibrary klib(QLatin1String("libkdeinit4_") + lib, *s_instance );
485  libpath = klib.fileName();
486  if( libpath.isEmpty()) {
487  KLibrary klib(lib, *s_instance);
488  libpath = klib.fileName();
489  }
490  execpath = execpath_avoid_loops(exec, envc, envs, avoid_loops);
491  } else {
492  name = _name;
493  lib = QFile::decodeName(name);
494  name = name.mid(name.lastIndexOf('/') + 1);
495  exec = _name;
496  if (lib.endsWith(QLatin1String(".so")))
497  libpath = lib;
498  else {
499  // try to match an absolute path to an executable binary (either in bin/ or in libexec/)
500  // to a kdeinit module in the same prefix
501  if( lib.contains( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ))) {
502  libpath = QString( lib ).replace( QLatin1String( "/lib" KDELIBSUFF "/kde4/libexec/" ),
503  QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so");
504  } else if( lib.contains( QLatin1String( "/bin/" ))) {
505  libpath = QString( lib ).replace( QLatin1String( "/bin/" ),
506  QLatin1String("/lib" KDELIBSUFF "/libkdeinit4_")) + QLatin1String(".so");
507  }
508  // Don't confuse the user with "Could not load libkdeinit4_foo.so" if it doesn't exist
509  if (!QFile::exists(libpath)) {
510  libpath.clear();
511  }
512  execpath = exec;
513  }
514  }
515 #ifndef NDEBUG
516  fprintf(stderr,"kdeinit4: preparing to launch %s\n", libpath.isEmpty()
517  ? execpath.constData() : libpath.toUtf8().constData());
518 #endif
519  if (!args) {
520  argc = 1;
521  }
522 
523  if (0 > pipe(d.fd))
524  {
525  perror("kdeinit4: pipe() failed");
526  d.result = 3;
527  d.errorMsg = i18n("Unable to start new process.\n"
528  "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();
529  d.fork = 0;
530  return d.fork;
531  }
532 
533 #ifdef Q_WS_X11
534  KStartupInfoId startup_id;
535  startup_id.initId( startup_id_str );
536  if( !startup_id.none())
537  init_startup_info( startup_id, name, envc, envs );
538 #endif
539  // find out these paths before forking, doing it afterwards
540  // crashes on some platforms, notably OSX
541  const QByteArray docPath = QFile::encodeName(KGlobalSettings::documentPath());
542 #ifdef Q_WS_MAC
543  const QString bundlepath = s_instance->dirs()->findExe(QFile::decodeName(execpath));
544 #endif
545 
546  d.errorMsg = 0;
547  d.fork = fork();
548  switch(d.fork) {
549  case -1:
550  perror("kdeinit4: fork() failed");
551  d.result = 3;
552  d.errorMsg = i18n("Unable to create new process.\n"
553  "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();
554  close(d.fd[0]);
555  close(d.fd[1]);
556  d.fork = 0;
557  break;
558  case 0:
559  {
561  close(d.fd[0]);
562  close_fds();
563  reset_oom_protect();
564 
565  // Try to chdir, either to the requested directory or to the user's document path by default.
566  // We ignore errors - if you write a desktop file with Exec=foo and Path=/doesnotexist,
567  // we still want to execute `foo` even if the chdir() failed.
568  if (cwd && *cwd) {
569  (void)chdir(cwd);
570  } else {
571  // on Maemo5, documentPath() is on the SD card, setting it as working directory would block
572  // USB mass storage access
573 #ifndef Q_WS_MAEMO_5
574  (void)chdir(docPath.constData());
575 #endif
576  }
577 
578  if( reset_env ) // KWRAPPER/SHELL
579  {
580 
581  QList<QByteArray> unset_envs;
582  for( int tmp_env_count = 0;
583  environ[tmp_env_count];
584  tmp_env_count++)
585  unset_envs.append( environ[ tmp_env_count ] );
586  foreach(const QByteArray &tmp, unset_envs)
587  {
588  int pos = tmp.indexOf( '=' );
589  if( pos >= 0 )
590  unsetenv( tmp.left( pos ));
591  }
592  }
593 
594  for (int i = 0; i < envc; i++)
595  {
596  putenv((char *)envs);
597  while(*envs != 0) envs++;
598  envs++;
599  }
600 
601 #ifdef Q_WS_X11
602  if( startup_id.none())
603  KStartupInfo::resetStartupEnv();
604  else
605  startup_id.setupStartupEnv();
606 #endif
607  {
608  int r;
609  QByteArray procTitle;
610  d.argv = (char **) malloc(sizeof(char *) * (argc+1));
611  d.argv[0] = (char *) _name;
612 #ifdef Q_WS_MAC
613  QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0]));
614  if (!argvexe.isEmpty()) {
615  QByteArray cstr = argvexe.toLocal8Bit();
616  kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data();
617  d.argv[0] = strdup(cstr.data());
618  }
619 #endif
620  for (int i = 1; i < argc; i++)
621  {
622  d.argv[i] = (char *) args;
623  procTitle += ' ';
624  procTitle += (char *) args;
625  while(*args != 0) args++;
626  args++;
627  }
628  d.argv[argc] = 0;
629 
630 #ifndef SKIP_PROCTITLE
631 
632 #ifdef Q_OS_LINUX
633  /* set the process name, so that killall works like intended */
634  r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0);
635  if ( r == 0 )
636  proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" );
637  else
638  proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
639 #else
640  proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
641 #endif
642 #endif
643  }
644 
645  if (libpath.isEmpty() && execpath.isEmpty())
646  {
647  QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name));
648  exitWithErrorMsg(errorMsg);
649  }
650 
651 
652  if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty())
653  libpath.truncate(0);
654 
655  QLibrary l(libpath);
656 
657  if ( !libpath.isEmpty() )
658  {
659  if (!l.load() || !l.isLoaded() )
660  {
661  QString ltdlError (l.errorString());
662  if (execpath.isEmpty())
663  {
664  // Error
665  QString errorMsg = i18n("Could not open library '%1'.\n%2", libpath, ltdlError);
666  exitWithErrorMsg(errorMsg);
667  }
668  else
669  {
670  // Print warning
671  fprintf(stderr, "Could not open library %s: %s\n", qPrintable(lib),
672  qPrintable(ltdlError) );
673  }
674  }
675  }
676  if (!l.isLoaded())
677  {
678  d.result = 2; // Try execing
679  write(d.fd[1], &d.result, 1);
680 
681  // We set the close on exec flag.
682  // Closing of d.fd[1] indicates that the execvp succeeded!
683  fcntl(d.fd[1], F_SETFD, FD_CLOEXEC);
684 
685  setup_tty( tty );
686 
687  QByteArray executable = execpath;
688 #ifdef Q_WS_MAC
689  if (!bundlepath.isEmpty())
690  executable = QFile::encodeName(bundlepath);
691 #endif
692 
693  if (!executable.isEmpty())
694  execvp(executable, d.argv);
695 
696  d.result = 1; // Error
697  write(d.fd[1], &d.result, 1);
698  close(d.fd[1]);
699  exit(255);
700  }
701 
702  void * sym = l.resolve( "kdeinitmain");
703  if (!sym )
704  {
705  sym = l.resolve( "kdemain" );
706  if ( !sym )
707  {
708  QString ltdlError = l.errorString();
709  fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) );
710  QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2",
711  libpath, ltdlError);
712  exitWithErrorMsg(errorMsg);
713  }
714  }
715 
716  d.result = 0; // Success
717  write(d.fd[1], &d.result, 1);
718  close(d.fd[1]);
719 
720  d.func = (int (*)(int, char *[])) sym;
721  if (d.debug_wait)
722  {
723  fprintf(stderr, "kdeinit4: Suspending process\n"
724  "kdeinit4: 'gdb kdeinit4 %d' to debug\n"
725  "kdeinit4: 'kill -SIGCONT %d' to continue\n",
726  getpid(), getpid());
727  kill(getpid(), SIGSTOP);
728  }
729  else
730  {
731  setup_tty( tty );
732  }
733 
734  exit( d.func(argc, d.argv)); /* Launch! */
735 
736  break;
737  }
738  default:
740  close(d.fd[1]);
741  bool exec = false;
742  for(;;)
743  {
744  d.n = read(d.fd[0], &d.result, 1);
745  if (d.n == 1)
746  {
747  if (d.result == 2)
748  {
749 #ifndef NDEBUG
750  //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n");
751 #endif
752  exec = true;
753  continue;
754  }
755  if (d.result == 3)
756  {
757  int l = 0;
758  d.n = read(d.fd[0], &l, sizeof(int));
759  if (d.n == sizeof(int))
760  {
761  QByteArray tmp;
762  tmp.resize(l+1);
763  d.n = read(d.fd[0], tmp.data(), l);
764  tmp[l] = 0;
765  if (d.n == l)
766  d.errorMsg = tmp;
767  }
768  }
769  // Finished
770  break;
771  }
772  if (d.n == -1)
773  {
774  if (errno == ECHILD) { // a child died.
775  continue;
776  }
777  if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read
778  continue;
779  }
780  }
781  if (d.n == 0)
782  {
783  if (exec) {
784  d.result = 0;
785  } else {
786  fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData());
787  perror("kdeinit4: Pipe closed unexpectedly");
788  d.result = 1; // Error
789  }
790  break;
791  }
792  perror("kdeinit4: Error reading from pipe");
793  d.result = 1; // Error
794  break;
795  }
796  close(d.fd[0]);
797  }
798 #ifdef Q_WS_X11
799  if( !startup_id.none())
800  {
801  if( d.fork && d.result == 0 ) // launched successfully
802  complete_startup_info( startup_id, d.fork );
803  else // failure, cancel ASN
804  complete_startup_info( startup_id, 0 );
805  }
806 #endif
807  return d.fork;
808 }
809 
810 extern "C" {
811 
812 static void sig_child_handler(int)
813 {
814  /*
815  * Write into the pipe of death.
816  * This way we are sure that we return from the select()
817  *
818  * A signal itself causes select to return as well, but
819  * this creates a race-condition in case the signal arrives
820  * just before we enter the select.
821  */
822  char c = 0;
823  write(d.deadpipe[1], &c, 1);
824 }
825 
826 }
827 
828 static void init_signals()
829 {
830  struct sigaction act;
831  long options;
832 
833  if (pipe(d.deadpipe) != 0)
834  {
835  perror("kdeinit4: Aborting. Can not create pipe");
836  exit(255);
837  }
838 
839  options = fcntl(d.deadpipe[0], F_GETFL);
840  if (options == -1)
841  {
842  perror("kdeinit4: Aborting. Can not make pipe non-blocking");
843  exit(255);
844  }
845 
846  if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1)
847  {
848  perror("kdeinit4: Aborting. Can not make pipe non-blocking");
849  exit(255);
850  }
851 
852  /*
853  * A SIGCHLD handler is installed which sends a byte into the
854  * pipe of death. This is to ensure that a dying child causes
855  * an exit from select().
856  */
857  act.sa_handler=sig_child_handler;
858  sigemptyset(&(act.sa_mask));
859  sigaddset(&(act.sa_mask), SIGCHLD);
860  sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
861  act.sa_flags = SA_NOCLDSTOP;
862 
863  // CC: take care of SunOS which automatically restarts interrupted system
864  // calls (and thus does not have SA_RESTART)
865 
866 #ifdef SA_RESTART
867  act.sa_flags |= SA_RESTART;
868 #endif
869  sigaction( SIGCHLD, &act, 0L);
870 
871  act.sa_handler=SIG_IGN;
872  sigemptyset(&(act.sa_mask));
873  sigaddset(&(act.sa_mask), SIGPIPE);
874  sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
875  act.sa_flags = 0;
876  sigaction( SIGPIPE, &act, 0L);
877 }
878 
879 static void init_kdeinit_socket()
880 {
881  struct sockaddr_un sa;
882  kde_socklen_t socklen;
883  long options;
884  const QByteArray home_dir = qgetenv("HOME");
885  int max_tries = 10;
886  if (home_dir.isEmpty())
887  {
888  fprintf(stderr, "kdeinit4: Aborting. $HOME not set!");
889  exit(255);
890  }
891  if (chdir(home_dir) != 0) {
892  fprintf(stderr, "kdeinit4: Aborting. Couldn't enter '%s'!", home_dir.constData());
893  exit(255);
894  }
895 
896  {
897  QByteArray path = home_dir;
898  QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
899  if (access(path.data(), R_OK|W_OK))
900  {
901  if (errno == ENOENT)
902  {
903  fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data());
904  exit(255);
905  }
906  else if (readOnly.isEmpty())
907  {
908  fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data());
909  exit(255);
910  }
911  }
912 #if 0 // obsolete in kde4. Should we check writing to another file instead?
913  path = qgetenv("ICEAUTHORITY");
914  if (path.isEmpty())
915  {
916  path = home_dir;
917  path += "/.ICEauthority";
918  }
919  if (access(path.data(), R_OK|W_OK) && (errno != ENOENT))
920  {
921  fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data());
922  exit(255);
923  }
924 #endif
925  }
926 
931  if (access(sock_file, W_OK) == 0)
932  {
933  int s;
934  struct sockaddr_un server;
935 
936 // fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n");
937  /*
938  * create the socket stream
939  */
940  s = socket(PF_UNIX, SOCK_STREAM, 0);
941  if (s < 0)
942  {
943  perror("socket() failed");
944  exit(255);
945  }
946  server.sun_family = AF_UNIX;
947  strcpy(server.sun_path, sock_file);
948  socklen = sizeof(server);
949 
950  if(connect(s, (struct sockaddr *)&server, socklen) == 0)
951  {
952  fprintf(stderr, "kdeinit4: Shutting down running client.\n");
953  klauncher_header request_header;
954  request_header.cmd = LAUNCHER_TERMINATE_KDEINIT;
955  request_header.arg_length = 0;
956  write(s, &request_header, sizeof(request_header));
957  sleep(1); // Give it some time
958  }
959  close(s);
960  }
961 
963  unlink(sock_file);
964 
966  d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0);
967  if (d.wrapper < 0)
968  {
969  perror("kdeinit4: Aborting. socket() failed");
970  exit(255);
971  }
972 
973  options = fcntl(d.wrapper, F_GETFL);
974  if (options == -1)
975  {
976  perror("kdeinit4: Aborting. Can not make socket non-blocking");
977  close(d.wrapper);
978  exit(255);
979  }
980 
981  if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1)
982  {
983  perror("kdeinit4: Aborting. Can not make socket non-blocking");
984  close(d.wrapper);
985  exit(255);
986  }
987 
988  while (1) {
990  socklen = sizeof(sa);
991  memset(&sa, 0, socklen);
992  sa.sun_family = AF_UNIX;
993  strcpy(sa.sun_path, sock_file);
994  if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0)
995  {
996  if (max_tries == 0) {
997  perror("kdeinit4: Aborting. bind() failed");
998  fprintf(stderr, "Could not bind to socket '%s'\n", sock_file);
999  close(d.wrapper);
1000  exit(255);
1001  }
1002  max_tries--;
1003  } else
1004  break;
1005  }
1006 
1008  if (chmod(sock_file, 0600) != 0)
1009  {
1010  perror("kdeinit4: Aborting. Can not set permissions on socket");
1011  fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
1012  unlink(sock_file);
1013  close(d.wrapper);
1014  exit(255);
1015  }
1016 
1017  if(listen(d.wrapper, SOMAXCONN) < 0)
1018  {
1019  perror("kdeinit4: Aborting. listen() failed");
1020  unlink(sock_file);
1021  close(d.wrapper);
1022  exit(255);
1023  }
1024 }
1025 
1026 /*
1027  * Read 'len' bytes from 'sock' into buffer.
1028  * returns 0 on success, -1 on failure.
1029  */
1030 static int read_socket(int sock, char *buffer, int len)
1031 {
1032  ssize_t result;
1033  int bytes_left = len;
1034  while ( bytes_left > 0)
1035  {
1036  result = read(sock, buffer, bytes_left);
1037  if (result > 0)
1038  {
1039  buffer += result;
1040  bytes_left -= result;
1041  }
1042  else if (result == 0)
1043  return -1;
1044  else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
1045  return -1;
1046  }
1047  return 0;
1048 }
1049 
1050 static void start_klauncher()
1051 {
1052  if (socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher) < 0) {
1053  perror("kdeinit4: socketpair() failed");
1054  exit(255);
1055  }
1056  char args[32];
1057  strcpy(args, "--fd=");
1058  sprintf(args + 5, "%d", d.launcher[1]);
1059  d.launcher_pid = launch( 2, "klauncher", args );
1060  close(d.launcher[1]);
1061 #ifndef NDEBUG
1062  fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld, result = %d\n",
1063  (long) d.launcher_pid, d.result);
1064 #endif
1065 }
1066 
1067 static void launcher_died()
1068 {
1069  if (!d.launcher_ok)
1070  {
1071  /* This is bad. */
1072  fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
1073  ::exit(255);
1074  return;
1075  }
1076 
1077  // KLauncher died... restart
1078 #ifndef NDEBUG
1079  fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
1080 #endif
1081  // Make sure it's really dead.
1082  if (d.launcher_pid)
1083  {
1084  kill(d.launcher_pid, SIGKILL);
1085  sleep(1); // Give it some time
1086  }
1087 
1088  d.launcher_ok = false;
1089  d.launcher_pid = 0;
1090  close(d.launcher[0]);
1091  d.launcher[0] = -1;
1092 
1093  start_klauncher();
1094 }
1095 
1096 static bool handle_launcher_request(int sock, const char *who)
1097 {
1098  (void)who; // for NDEBUG
1099 
1100  klauncher_header request_header;
1101  char *request_data = 0L;
1102  int result = read_socket(sock, (char *) &request_header, sizeof(request_header));
1103  if (result != 0)
1104  {
1105  return false;
1106  }
1107 
1108  if ( request_header.arg_length != 0 )
1109  {
1110  request_data = (char *) malloc(request_header.arg_length);
1111 
1112  result = read_socket(sock, request_data, request_header.arg_length);
1113  if (result != 0)
1114  {
1115  free(request_data);
1116  return false;
1117  }
1118  }
1119 
1120  //kDebug() << "Got cmd" << request_header.cmd << commandToString(request_header.cmd);
1121  if (request_header.cmd == LAUNCHER_OK)
1122  {
1123  d.launcher_ok = true;
1124  }
1125  else if (request_header.arg_length &&
1126  ((request_header.cmd == LAUNCHER_EXEC) ||
1127  (request_header.cmd == LAUNCHER_EXT_EXEC) ||
1128  (request_header.cmd == LAUNCHER_SHELL ) ||
1129  (request_header.cmd == LAUNCHER_KWRAPPER) ||
1130  (request_header.cmd == LAUNCHER_EXEC_NEW)))
1131  {
1132  pid_t pid;
1133  klauncher_header response_header;
1134  long response_data;
1135  long l;
1136  memcpy( &l, request_data, sizeof( long ));
1137  int argc = l;
1138  const char *name = request_data + sizeof(long);
1139  const char *args = name + strlen(name) + 1;
1140  const char *cwd = 0;
1141  int envc = 0;
1142  const char *envs = 0;
1143  const char *tty = 0;
1144  int avoid_loops = 0;
1145  const char *startup_id_str = "0"; // krazy:exclude=doublequote_chars
1146 
1147 #ifndef NDEBUG
1148  fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n",
1149  commandToString(request_header.cmd),
1150  name, who);
1151 #endif
1152 
1153  const char *arg_n = args;
1154  for(int i = 1; i < argc; i++)
1155  {
1156  arg_n = arg_n + strlen(arg_n) + 1;
1157  }
1158 
1159  if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER )
1160  {
1161  // Shell or kwrapper
1162  cwd = arg_n; arg_n += strlen(cwd) + 1;
1163  }
1164  if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
1165  || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
1166  {
1167  memcpy( &l, arg_n, sizeof( long ));
1168  envc = l;
1169  arg_n += sizeof(long);
1170  envs = arg_n;
1171  for(int i = 0; i < envc; i++)
1172  {
1173  arg_n = arg_n + strlen(arg_n) + 1;
1174  }
1175  if( request_header.cmd == LAUNCHER_KWRAPPER )
1176  {
1177  tty = arg_n;
1178  arg_n += strlen( tty ) + 1;
1179  }
1180  }
1181 
1182  if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
1183  || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
1184  {
1185  memcpy( &l, arg_n, sizeof( long ));
1186  avoid_loops = l;
1187  arg_n += sizeof( long );
1188  }
1189 
1190  if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
1191  || request_header.cmd == LAUNCHER_EXT_EXEC )
1192  {
1193  startup_id_str = arg_n;
1194  arg_n += strlen( startup_id_str ) + 1;
1195  }
1196 
1197  if ((request_header.arg_length > (arg_n - request_data)) &&
1198  (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ))
1199  {
1200  // Optional cwd
1201  cwd = arg_n; arg_n += strlen(cwd) + 1;
1202  }
1203 
1204  if ((arg_n - request_data) != request_header.arg_length)
1205  {
1206 #ifndef NDEBUG
1207  fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n");
1208 #endif
1209  free(request_data);
1210  d.debug_wait = false;
1211  return true; // sure?
1212  }
1213 
1214  // support for the old a bit broken way of setting DISPLAY for multihead
1215  QByteArray olddisplay = qgetenv(DISPLAY);
1216  QByteArray kdedisplay = qgetenv("KDE_DISPLAY");
1217  bool reset_display = (! olddisplay.isEmpty() &&
1218  ! kdedisplay.isEmpty() &&
1219  olddisplay != kdedisplay);
1220 
1221  if (reset_display)
1222  setenv(DISPLAY, kdedisplay, true);
1223 
1224  pid = launch( argc, name, args, cwd, envc, envs,
1225  request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER,
1226  tty, avoid_loops, startup_id_str );
1227 
1228  if (reset_display) {
1229  unsetenv("KDE_DISPLAY");
1230  setenv(DISPLAY, olddisplay, true);
1231  }
1232 
1233  if (pid && (d.result == 0))
1234  {
1235  response_header.cmd = LAUNCHER_OK;
1236  response_header.arg_length = sizeof(response_data);
1237  response_data = pid;
1238  write(sock, &response_header, sizeof(response_header));
1239  write(sock, &response_data, response_header.arg_length);
1240 
1241  /* add new child to list */
1242  struct child *child = (struct child *) malloc(sizeof(struct child));
1243  child->pid = pid;
1244  child->sock = dup(sock);
1245  child->next = children;
1246  children = child;
1247  }
1248  else
1249  {
1250  int l = d.errorMsg.length();
1251  if (l) l++; // Include trailing null.
1252  response_header.cmd = LAUNCHER_ERROR;
1253  response_header.arg_length = l;
1254  write(sock, &response_header, sizeof(response_header));
1255  if (l)
1256  write(sock, d.errorMsg.data(), l);
1257  }
1258  d.debug_wait = false;
1259  }
1260  else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV)
1261  {
1262  const char *env_name;
1263  const char *env_value;
1264  env_name = request_data;
1265  env_value = env_name + strlen(env_name) + 1;
1266 
1267 #ifndef NDEBUG
1268  fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from %s.\n", env_name, env_value, who);
1269 #endif
1270 
1271  if ( request_header.arg_length !=
1272  (int) (strlen(env_name) + strlen(env_value) + 2))
1273  {
1274 #ifndef NDEBUG
1275  fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n");
1276 #endif
1277  free(request_data);
1278  return true; // sure?
1279  }
1280  setenv( env_name, env_value, 1);
1281  }
1282  else if (request_header.cmd == LAUNCHER_TERMINATE_KDE)
1283  {
1284 #ifndef NDEBUG
1285  fprintf(stderr,"kdeinit4: terminate KDE.\n");
1286 #endif
1287 #ifdef Q_WS_X11
1288  kdeinit_xio_errhandler( 0L );
1289 #endif
1290  }
1291  else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT)
1292  {
1293 #ifndef NDEBUG
1294  fprintf(stderr,"kdeinit4: Got termination request (PID %ld).\n", (long) getpid());
1295 #endif
1296  if (d.launcher_pid) {
1297  kill(d.launcher_pid, SIGTERM);
1298  d.launcher_pid = 0;
1299  close(d.launcher[0]);
1300  d.launcher[0] = -1;
1301  }
1302  unlink(sock_file);
1303  if (children) {
1304  close(d.wrapper);
1305  d.wrapper = -1;
1306 #ifndef NDEBUG
1307  fprintf(stderr,"kdeinit4: Closed sockets, but not exiting until all children terminate.\n");
1308 #endif
1309  } else {
1310  raise(SIGTERM);
1311  }
1312  }
1313  else if (request_header.cmd == LAUNCHER_DEBUG_WAIT)
1314  {
1315 #ifndef NDEBUG
1316  fprintf(stderr,"kdeinit4: Debug wait activated.\n");
1317 #endif
1318  d.debug_wait = true;
1319  }
1320  if (request_data)
1321  free(request_data);
1322  return true;
1323 }
1324 
1325 static void handle_requests(pid_t waitForPid)
1326 {
1327  int max_sock = d.deadpipe[0];
1328  if (d.wrapper > max_sock)
1329  max_sock = d.wrapper;
1330  if (d.launcher[0] > max_sock)
1331  max_sock = d.launcher[0];
1332 #ifdef Q_WS_X11
1333  if (X11fd > max_sock)
1334  max_sock = X11fd;
1335 #endif
1336  max_sock++;
1337 
1338  while(1)
1339  {
1340  fd_set rd_set;
1341  fd_set wr_set;
1342  fd_set e_set;
1343  int result;
1344  pid_t exit_pid;
1345  int exit_status;
1346  char c;
1347 
1348  /* Flush the pipe of death */
1349  while( read(d.deadpipe[0], &c, 1) == 1)
1350  {}
1351 
1352  /* Handle dying children */
1353  do {
1354  exit_pid = waitpid(-1, &exit_status, WNOHANG);
1355  if (exit_pid > 0)
1356  {
1357 #ifndef NDEBUG
1358  fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid);
1359 #endif
1360  if (waitForPid && (exit_pid == waitForPid))
1361  return;
1362 
1363  if( WIFEXITED( exit_status )) // fix process return value
1364  exit_status = WEXITSTATUS(exit_status);
1365  else if( WIFSIGNALED(exit_status))
1366  exit_status = 128 + WTERMSIG( exit_status );
1367  child_died(exit_pid, exit_status);
1368 
1369  if (d.wrapper < 0 && !children) {
1370 #ifndef NDEBUG
1371  fprintf(stderr, "kdeinit4: Last child terminated, exiting (PID %ld).\n",
1372  (long) getpid());
1373 #endif
1374  raise(SIGTERM);
1375  }
1376  }
1377  }
1378  while( exit_pid > 0);
1379 
1380  FD_ZERO(&rd_set);
1381  FD_ZERO(&wr_set);
1382  FD_ZERO(&e_set);
1383 
1384  if (d.launcher[0] >= 0)
1385  FD_SET(d.launcher[0], &rd_set);
1386  if (d.wrapper >= 0)
1387  FD_SET(d.wrapper, &rd_set);
1388  FD_SET(d.deadpipe[0], &rd_set);
1389 #ifdef Q_WS_X11
1390  if(X11fd >= 0) FD_SET(X11fd, &rd_set);
1391 #endif
1392 
1393  result = select(max_sock, &rd_set, &wr_set, &e_set, 0);
1394  if (result < 0) {
1395  if (errno == EINTR || errno == EAGAIN)
1396  continue;
1397  perror("kdeinit4: Aborting. select() failed");
1398  return;
1399  }
1400 
1401  /* Handle wrapper request */
1402  if (d.wrapper >= 0 && FD_ISSET(d.wrapper, &rd_set))
1403  {
1404  struct sockaddr_un client;
1405  kde_socklen_t sClient = sizeof(client);
1406  int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient);
1407  if (sock >= 0)
1408  {
1409  d.accepted_fd = sock;
1410  handle_launcher_request(sock, "wrapper");
1411  close(sock);
1412  d.accepted_fd = -1;
1413  }
1414  }
1415 
1416  /* Handle launcher request */
1417  if (d.launcher[0] >= 0 && FD_ISSET(d.launcher[0], &rd_set))
1418  {
1419  if (!handle_launcher_request(d.launcher[0], "launcher"))
1420  launcher_died();
1421  if (waitForPid == d.launcher_pid)
1422  return;
1423  }
1424 
1425 #ifdef Q_WS_X11
1426  /* Look for incoming X11 events */
1427  if(X11fd >= 0 && FD_ISSET(X11fd,&rd_set)) {
1428  if (X11display != 0) {
1429  XEvent event_return;
1430  while (XPending(X11display))
1431  XNextEvent(X11display, &event_return);
1432  }
1433  }
1434 #endif
1435  }
1436 }
1437 
1438 static void kdeinit_library_path()
1439 {
1440  const QStringList ltdl_library_path =
1441  QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(QLatin1Char(':'),QString::SkipEmptyParts);
1442 #ifdef Q_OS_DARWIN
1443  const QByteArray ldlibpath = qgetenv("DYLD_LIBRARY_PATH");
1444 #else
1445  const QByteArray ldlibpath = qgetenv("LD_LIBRARY_PATH");
1446 #endif
1447  const QStringList ld_library_path =
1448  QFile::decodeName(ldlibpath).split(QLatin1Char(':'),QString::SkipEmptyParts);
1449 
1450  QByteArray extra_path;
1451  const QStringList candidates = s_instance->dirs()->resourceDirs("lib");
1452  for (QStringList::ConstIterator it = candidates.begin();
1453  it != candidates.end();
1454  ++it)
1455  {
1456  QString d = *it;
1457  if (ltdl_library_path.contains(d))
1458  continue;
1459  if (ld_library_path.contains(d))
1460  continue;
1461  if (d[d.length()-1] == QLatin1Char('/'))
1462  {
1463  d.truncate(d.length()-1);
1464  if (ltdl_library_path.contains(d))
1465  continue;
1466  if (ld_library_path.contains(d))
1467  continue;
1468  }
1469  if ((d == QLatin1String("/lib")) || (d == QLatin1String("/usr/lib")))
1470  continue;
1471 
1472  QByteArray dir = QFile::encodeName(d);
1473 
1474  if (access(dir, R_OK))
1475  continue;
1476 
1477  if ( !extra_path.isEmpty())
1478  extra_path += ':';
1479  extra_path += dir;
1480  }
1481 
1482 // if (!extra_path.isEmpty())
1483 // lt_dlsetsearchpath(extra_path.data());
1484 
1485  QByteArray display = qgetenv(DISPLAY);
1486  if (display.isEmpty())
1487  {
1488 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
1489  fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n");
1490  exit(255);
1491 #endif
1492  }
1493  int i;
1494  if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
1495  display.truncate(i);
1496 
1497  display.replace(':','_');
1498 #ifdef __APPLE__
1499  display.replace('/','_');
1500 #endif
1501  // WARNING, if you change the socket name, adjust kwrapper too
1502  const QString socketFileName = QString::fromLatin1("kdeinit4_%1").arg(QLatin1String(display));
1503  QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", socketFileName, *s_instance));
1504  if (socketName.length() >= MAX_SOCK_FILE)
1505  {
1506  fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
1507  fprintf(stderr, " '%s'\n", socketName.data());
1508  exit(255);
1509  }
1510  strcpy(sock_file, socketName.data());
1511 }
1512 
1513 int kdeinit_xio_errhandler( Display *disp )
1514 {
1515  // disp is 0L when KDE shuts down. We don't want those warnings then.
1516 
1517  if ( disp )
1518  qWarning( "kdeinit4: Fatal IO error: client killed" );
1519 
1520  if (sock_file[0])
1521  {
1523  unlink(sock_file);
1524  }
1525 
1526  // Don't kill our children in suicide mode, they may still be in use
1527  if (d.suicide)
1528  {
1529  if (d.launcher_pid)
1530  kill(d.launcher_pid, SIGTERM);
1531  if (d.kded_pid)
1532  kill(d.kded_pid, SIGTERM);
1533  exit( 0 );
1534  }
1535 
1536  if ( disp )
1537  qWarning( "kdeinit4: sending SIGHUP to children." );
1538 
1539  /* this should remove all children we started */
1540  KDE_signal(SIGHUP, SIG_IGN);
1541  kill(0, SIGHUP);
1542 
1543  sleep(2);
1544 
1545  if ( disp )
1546  qWarning( "kdeinit4: sending SIGTERM to children." );
1547 
1548  /* and if they don't listen to us, this should work */
1549  KDE_signal(SIGTERM, SIG_IGN);
1550  kill(0, SIGTERM);
1551 
1552  if ( disp )
1553  qWarning( "kdeinit4: Exit." );
1554 
1555  exit( 0 );
1556  return 0;
1557 }
1558 
1559 #ifdef Q_WS_X11
1560 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err )
1561 {
1562 #ifndef NDEBUG
1563  char errstr[256];
1564  // kdeinit almost doesn't use X, and therefore there shouldn't be any X error
1565  XGetErrorText( dpy, err->error_code, errstr, 256 );
1566  fprintf(stderr, "kdeinit4(%d) : KDE detected X Error: %s %d\n"
1567  " Major opcode: %d\n"
1568  " Minor opcode: %d\n"
1569  " Resource id: 0x%lx\n",
1570  getpid(), errstr, err->error_code, err->request_code, err->minor_code, err->resourceid );
1571 
1572  //kDebug() << kBacktrace();
1573 
1574 #else
1575  Q_UNUSED(dpy);
1576  Q_UNUSED(err);
1577 #endif
1578  return 0;
1579 }
1580 #endif
1581 
1582 #ifdef Q_WS_X11
1583 // needs to be done sooner than initXconnection() because of also opening
1584 // another X connection for startup notification purposes
1585 static void setupX()
1586 {
1587  XSetIOErrorHandler(kdeinit_xio_errhandler);
1588  XSetErrorHandler(kdeinit_x_errhandler);
1589 /*
1590  Handle the tricky case of running via kdesu/su/sudo/etc. There the usual case
1591  is that kdesu (etc.) creates a file with xauth information, sets XAUTHORITY,
1592  runs the command and removes the xauth file after the command finishes. However,
1593  dbus and kdeinit daemon currently don't clean up properly and keeping running.
1594  Which means that running a KDE app via kdesu the second time talks to kdeinit
1595  with obsolete xauth information, which makes it unable to connect to X or launch
1596  any X11 applications.
1597  Even fixing the cleanup probably wouldn't be sufficient, since it'd be possible to
1598  launch one kdesu session, another one, exit the first one and the app from the second
1599  session would be using kdeinit from the first one.
1600  So the trick here is to duplicate the xauth file to another file in KDE's tmp
1601  location, make the file have a consistent name so that future sessions will use it
1602  as well, point XAUTHORITY there and never remove the file (except for possible
1603  tmp cleanup).
1604 */
1605  if( !qgetenv( "XAUTHORITY" ).isEmpty()) {
1606  QByteArray display = qgetenv( DISPLAY );
1607  int i;
1608  if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
1609  display.truncate(i);
1610  display.replace(':','_');
1611 #ifdef __APPLE__
1612  display.replace('/','_');
1613 #endif
1614  QString xauth = s_instance->dirs()->saveLocation( "tmp" ) + QLatin1String( "xauth-" )
1615  + QString::number( getuid()) + QLatin1String( "-" ) + QString::fromLocal8Bit( display );
1616  KSaveFile xauthfile( xauth );
1617  QFile xauthfrom( QFile::decodeName( qgetenv( "XAUTHORITY" )));
1618  if( !xauthfrom.open( QFile::ReadOnly ) || !xauthfile.open( QFile::WriteOnly )
1619  || xauthfile.write( xauthfrom.readAll()) != xauthfrom.size() || !xauthfile.finalize()) {
1620  xauthfile.abort();
1621  } else {
1622  setenv( "XAUTHORITY", QFile::encodeName( xauth ), true );
1623  }
1624  }
1625 }
1626 
1627 // Borrowed from kdebase/kaudio/kaudioserver.cpp
1628 static int initXconnection()
1629 {
1630  X11display = XOpenDisplay(NULL);
1631  if ( X11display != 0 ) {
1632  XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \
1633  0,
1634  BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)),
1635  BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) );
1636 #ifndef NDEBUG
1637  fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display));
1638 #endif
1639  int fd = XConnectionNumber( X11display );
1640  int on = 1;
1641  (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on));
1642  return fd;
1643  } else
1644  fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \
1645  "kdeinit4: Might not terminate at end of session.\n");
1646 
1647  return -1;
1648 }
1649 #endif
1650 
1651 extern "C" {
1652 
1653 static void secondary_child_handler(int)
1654 {
1655  waitpid(-1, 0, WNOHANG);
1656 }
1657 
1658 }
1659 
1660 int main(int argc, char **argv, char **envp)
1661 {
1662 #ifndef _WIN32_WCE
1663  setlocale (LC_ALL, "");
1664  setlocale (LC_NUMERIC, "C");
1665 #endif
1666 
1667  pid_t pid;
1668  bool do_fork = true;
1669  int launch_klauncher = 1;
1670  int launch_kded = 1;
1671  int keep_running = 1;
1672  d.suicide = false;
1673 
1675  char **safe_argv = (char **) malloc( sizeof(char *) * argc);
1676  for(int i = 0; i < argc; i++)
1677  {
1678  safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
1679  if (strcmp(safe_argv[i], "--no-klauncher") == 0)
1680  launch_klauncher = 0;
1681  if (strcmp(safe_argv[i], "--no-kded") == 0)
1682  launch_kded = 0;
1683 #ifdef Q_WS_MACX
1684  // make it nofork to match KUniqueApplication, technically command-line incompatible
1685  if (strcmp(safe_argv[i], "--nofork") == 0)
1686 #else
1687  if (strcmp(safe_argv[i], "--no-fork") == 0)
1688 #endif
1689  do_fork = false;
1690  if (strcmp(safe_argv[i], "--suicide") == 0)
1691  d.suicide = true;
1692  if (strcmp(safe_argv[i], "--exit") == 0)
1693  keep_running = 0;
1694  if (strcmp(safe_argv[i], "--version") == 0)
1695  {
1696  printf("Qt: %s\n", qVersion());
1697  printf("KDE: %s\n", KDE_VERSION_STRING);
1698  exit(0);
1699  }
1700 #ifdef KDEINIT_OOM_PROTECT
1701  if (strcmp(safe_argv[i], "--oom-pipe") == 0 && i+1<argc)
1702  oom_pipe = atol(argv[i+1]);
1703 #endif
1704  if (strcmp(safe_argv[i], "--help") == 0)
1705  {
1706  printf("Usage: kdeinit4 [options]\n");
1707  // printf(" --no-dcop Do not start dcopserver\n");
1708 #ifdef Q_WS_MACX
1709  printf(" --nofork Do not fork\n");
1710 #else
1711  printf(" --no-fork Do not fork\n");
1712 #endif
1713  // printf(" --no-klauncher Do not start klauncher\n");
1714  printf(" --no-kded Do not start kded\n");
1715  printf(" --suicide Terminate when no KDE applications are left running\n");
1716  printf(" --version Show version information\n");
1717  // printf(" --exit Terminate when kded has run\n");
1718  exit(0);
1719  }
1720  }
1721 
1722  cleanup_fds();
1723 
1724  // Redirect stdout to stderr. We have no reason to use stdout anyway.
1725  // This minimizes our impact on commands used in pipes.
1726  (void)dup2(2, 1);
1727 
1728  if (do_fork) {
1729 #ifdef Q_WS_MACX
1730  mac_fork_and_reexec_self();
1731 #else
1732  if (pipe(d.initpipe) != 0) {
1733  perror("kdeinit4: pipe failed");
1734  return 1;
1735  }
1736 
1737  // Fork here and let parent process exit.
1738  // Parent process may only exit after all required services have been
1739  // launched. (dcopserver/klauncher and services which start with '+')
1740  KDE_signal( SIGCHLD, secondary_child_handler);
1741  if (fork() > 0) // Go into background
1742  {
1743  close(d.initpipe[1]);
1744  d.initpipe[1] = -1;
1745  // wait till init is complete
1746  char c;
1747  while( read(d.initpipe[0], &c, 1) < 0)
1748  ;
1749  // then exit;
1750  close(d.initpipe[0]);
1751  d.initpipe[0] = -1;
1752  return 0;
1753  }
1754  close(d.initpipe[0]);
1755  d.initpipe[0] = -1;
1756 #endif
1757  }
1758 
1760  if(keep_running)
1761  setsid();
1762 
1764  s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
1765 
1767 #ifndef SKIP_PROCTITLE
1768  proctitle_init(argc, argv, envp);
1769 #endif
1770 
1771  kdeinit_library_path();
1772  // Don't make our instance the global instance
1773  // (do it only after kdeinit_library_path, that one indirectly uses KConfig,
1774  // which seems to be buggy and always use KGlobal instead of the matching KComponentData)
1775  Q_ASSERT(!KGlobal::hasMainComponent());
1776  // don't change envvars before proctitle_init()
1777  unsetenv("LD_BIND_NOW");
1778  unsetenv("DYLD_BIND_AT_LAUNCH");
1779  KApplication::loadedByKdeinit = true;
1780 
1781  d.maxname = strlen(argv[0]);
1782  d.launcher_pid = 0;
1783  d.kded_pid = 0;
1784  d.wrapper = -1;
1785  d.accepted_fd = -1;
1786  d.debug_wait = false;
1787  d.launcher_ok = false;
1788  children = NULL;
1789  init_signals();
1790 #ifdef Q_WS_X11
1791  setupX();
1792 #endif
1793 
1794  if (keep_running)
1795  {
1796  /*
1797  * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper
1798  * requests.
1799  */
1800  init_kdeinit_socket();
1801  }
1802 #ifdef Q_WS_X11
1803  if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty()) {
1804  const int extrasCount = sizeof(extra_libs)/sizeof(extra_libs[0]);
1805  for (int i=0; i<extrasCount; i++) {
1806  QString extra = KStandardDirs::locate("lib", QLatin1String(extra_libs[i]), *s_instance);
1807 
1808  // can't use KLibLoader here as it would unload the library
1809  // again
1810  if (!extra.isEmpty()) {
1811  QLibrary l(extra);
1812  l.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1813  l.load();
1814  }
1815 #ifndef NDEBUG
1816  else {
1817  fprintf( stderr, "%s was not found.\n", extra_libs[i] );
1818  }
1819 #endif
1820 
1821  }
1822  }
1823 #endif
1824  if (launch_klauncher)
1825  {
1826  start_klauncher();
1827  handle_requests(d.launcher_pid); // Wait for klauncher to be ready
1828  }
1829 
1830 #ifdef Q_WS_X11
1831  X11fd = initXconnection();
1832 #endif
1833 
1834  {
1835  QFont::initialize();
1836 #ifdef Q_WS_X11
1837  if (XSupportsLocale ())
1838  {
1839  // Similar to QApplication::create_xim()
1840  // but we need to use our own display
1841  XOpenIM (X11display, 0, 0, 0);
1842  }
1843 #endif
1844  }
1845 
1846  if (launch_kded)
1847  {
1848  setenv("KDED_STARTED_BY_KDEINIT", "1", true);
1849  pid = launch( 1, KDED_EXENAME, 0 );
1850  unsetenv("KDED_STARTED_BY_KDEINIT");
1851 #ifndef NDEBUG
1852  fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result);
1853 #endif
1854  d.kded_pid = pid;
1855  handle_requests(pid);
1856  }
1857 
1858  for(int i = 1; i < argc; i++)
1859  {
1860  if (safe_argv[i][0] == '+')
1861  {
1862  pid = launch( 1, safe_argv[i]+1, 0);
1863 #ifndef NDEBUG
1864  fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result);
1865 #endif
1866  handle_requests(pid);
1867  }
1868  else if (safe_argv[i][0] == '-'
1869 #ifdef KDEINIT_OOM_PROTECT
1870  || isdigit(safe_argv[i][0])
1871 #endif
1872  )
1873  {
1874  // Ignore
1875  }
1876  else
1877  {
1878  pid = launch( 1, safe_argv[i], 0 );
1879 #ifndef NDEBUG
1880  fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result);
1881 #endif
1882  }
1883  }
1884 
1886  for(int i = 0; i < argc; i++)
1887  {
1888  free(safe_argv[i]);
1889  }
1890  free (safe_argv);
1891 
1892 #ifndef SKIP_PROCTITLE
1893  proctitle_set("kdeinit4 Running...");
1894 #endif
1895 
1896  if (!keep_running)
1897  return 0;
1898 
1899  if (d.initpipe[1] != -1)
1900  {
1901  char c = 0;
1902  write(d.initpipe[1], &c, 1); // Kdeinit is started.
1903  close(d.initpipe[1]);
1904  d.initpipe[1] = -1;
1905  }
1906 
1907  handle_requests(0);
1908 
1909  return 0;
1910 }
1911 
1912 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Nov 16 2012 15:00:53 by doxygen 1.8.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KInit

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

kdelibs-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal