• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeinit
 

tdeinit

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

tdeinit

Skip menu "tdeinit"
  • Main Page
  • File List
  • Related Pages

tdeinit

Skip menu "tdeinit"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeinit by doxygen 1.8.1.2
This website is maintained by Timothy Pearson.