• 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 <tdestandarddirs.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>
101extern "C" FcBool XftInitFtLibrary (void);
102#include <fontconfig/fontconfig.h>
103#endif
104
105extern char **environ;
106
107extern int lt_dlopen_flag;
108//#if defined TQ_WS_X11 && ! defined K_WS_QTONLY
109#ifdef TQ_WS_X11
110static int X11fd = -1;
111static Display *X11display = 0;
112static int X11_startup_notify_fd = -1;
113static Display *X11_startup_notify_display = 0;
114#endif
115static const TDEInstance *s_instance = 0;
116#define MAX_SOCK_FILE 255
117static char sock_file[MAX_SOCK_FILE];
118static 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 */
134static 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
162extern "C" {
163int tdeinit_xio_errhandler( Display * );
164int 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>
170extern "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>
173extern "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 */
179static 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
238static 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
251static 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
277static 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 =
301const 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
320static 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
338static 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
357TQCString 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
389static int oom_pipe = -1;
390
391static void oom_protect_sighandler( int ) {
392}
393
394static 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
416static void reset_oom_protect() {
417}
418#endif
419
420static 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
755static 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
769static 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
820static 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 */
1027static 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
1047static 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
1058static 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
1090static 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
1313static 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
1458static 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
1535int 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
1585int 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
1608static void setupX()
1609{
1610 XInitThreads();
1611 XSetIOErrorHandler(tdeinit_xio_errhandler);
1612 XSetErrorHandler(tdeinit_x_errhandler);
1613}
1614
1615// Borrowed from tdebase/kaudio/kaudioserver.cpp
1616static 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*/
1659extern "C" void _main(void);
1660extern "C" void __call_ctors__Fv(void);
1661static int main_called = 0;
1662void _main(void)
1663{
1664 if (main_called)
1665 return;
1666 main_called = 1;
1667 __call_ctors__Fv ();
1668}
1669#endif
1670
1671static void secondary_child_handler(int)
1672{
1673 waitpid(-1, 0, WNOHANG);
1674}
1675
1676int 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.8
This website is maintained by Timothy Pearson.