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

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeinit by doxygen 1.8.8
This website is maintained by Timothy Pearson.