• 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 <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 <tdeversion.h>
76
77#include "ltdl.h"
78#include "tdelauncher_cmds.h"
79
80//#if defined TQ_WS_X11 && ! defined K_WS_QTONLY
81#ifdef TQ_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>
103extern "C" FcBool XftInitFtLibrary (void);
104#include <fontconfig/fontconfig.h>
105#endif
106
107extern char **environ;
108
109extern int lt_dlopen_flag;
110//#if defined TQ_WS_X11 && ! defined K_WS_QTONLY
111#ifdef TQ_WS_X11
112static int X11fd = -1;
113static Display *X11display = 0;
114static int X11_startup_notify_fd = -1;
115static Display *X11_startup_notify_display = 0;
116#endif
117static const TDEInstance *s_instance = 0;
118#define MAX_SOCK_FILE 255
119static char sock_file[MAX_SOCK_FILE];
120static char sock_file_old[MAX_SOCK_FILE];
121
122//#if defined TQ_WS_X11 && ! defined K_WS_QTONLY
123#ifdef TQ_WS_X11
124#define DISPLAY "DISPLAY"
125#elif defined(TQ_WS_QWS)
126#define DISPLAY "QWS_DISPLAY"
127#elif defined(TQ_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 */
136static 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 TQ_WS_X11 && ! defined K_WS_QTONLY
163#ifdef TQ_WS_X11
164extern "C" {
165int tdeinit_xio_errhandler( Display * );
166int 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>
172extern "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>
175extern "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 */
181static 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 TQ_WS_X11 && ! defined K_WS_QTONLY
223//#ifdef TQ_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
240static 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
253static 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
279static int get_current_desktop( Display* disp )
280{
281 int desktop = 0; // no desktop by default
282#if defined TQ_WS_X11 && ! defined K_WS_QTONLY
283//#ifdef TQ_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 =
303const 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 TQ_WS_X11 && ! defined K_WS_QTONLY
321//#ifdef TQ_WS_X11 // FIXME(E): Implement for Qt/Embedded
322static 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
340static 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
359TQCString 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
391static int oom_pipe = -1;
392
393static void oom_protect_sighandler( int ) {
394}
395
396static 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
418static void reset_oom_protect() {
419}
420#endif
421
422static 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 TQ_WS_X11 && ! defined K_WS_QTONLY
485//#ifdef TQ_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 TQ_WS_X11 && ! defined K_WS_QTONLY
553//#ifdef TQ_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 TQ_WS_X11 && ! defined K_WS_QTONLY
748//#ifdef TQ_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
760static 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
774static 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
825static 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 */
1032static 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
1052static 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
1063static 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
1095static 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 TQ_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
1318static 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 TQ_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 TQ_WS_X11 && ! defined K_WS_QTONLY
1387//#ifdef TQ_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 TQ_WS_X11 && ! defined K_WS_QTONLY
1446#ifdef TQ_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
1463static 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
1540int 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 TQ_WS_X11
1590int 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 TQ_WS_X11 && ! defined K_WS_QTONLY
1610#ifdef TQ_WS_X11
1611// needs to be done sooner than initXconnection() because of also opening
1612// another X connection for startup notification purposes
1613static void setupX()
1614{
1615 XInitThreads();
1616 XSetIOErrorHandler(tdeinit_xio_errhandler);
1617 XSetErrorHandler(tdeinit_x_errhandler);
1618}
1619
1620// Borrowed from tdebase/kaudio/kaudioserver.cpp
1621static 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*/
1664extern "C" void _main(void);
1665extern "C" void __call_ctors__Fv(void);
1666static int main_called = 0;
1667void _main(void)
1668{
1669 if (main_called)
1670 return;
1671 main_called = 1;
1672 __call_ctors__Fv ();
1673}
1674#endif
1675
1676static void secondary_child_handler(int)
1677{
1678 waitpid(-1, 0, WNOHANG);
1679}
1680
1681int 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 TQ_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 TQ_WS_X11 && ! defined K_WS_QTONLY
1825//#ifdef TQ_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 TQ_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
  • 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.4
This website is maintained by Timothy Pearson.