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

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.9.1
This website is maintained by Timothy Pearson.