SVN_SILENT: oops, forgot to commit the xml tokenizer bit. Thanks Sebastian.
[kdelibs.git] / kinit / kinit.cpp
bloba32d659a7aa1a57a3dcc91467b594d896b10c14d
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>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License version 2 as published by the Free Software Foundation.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include <config.h>
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <sys/wait.h>
30 #ifdef HAVE_SYS_SELECT_H
31 #include <sys/select.h> // Needed on some systems.
32 #endif
34 #include <errno.h>
35 #include <fcntl.h>
36 #include "proctitle.h"
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <locale.h>
44 #include <QtCore/QLibrary>
45 #include <QtCore/QString>
46 #include <QtCore/QFile>
47 #include <QtCore/QDate>
48 #include <QtCore/QFileInfo>
49 #include <QtCore/QTextStream>
50 #include <QtCore/QRegExp>
51 #include <QtGui/QFont>
52 #include <QDir>
53 #include <kcomponentdata.h>
54 #include <kstandarddirs.h>
55 #include <kglobalsettings.h>
56 #include <kglobal.h>
57 #include <kconfig.h>
58 #include <klibloader.h>
59 #include <kapplication.h>
60 #include <klocale.h>
61 #include <kdebug.h>
62 #include <kde_file.h>
64 #ifdef Q_OS_LINUX
65 #include <sys/prctl.h>
66 #ifndef PR_SET_NAME
67 #define PR_SET_NAME 15
68 #endif
69 #endif
71 #ifdef Q_WS_MACX
72 #include <kkernel_mac.h>
73 #endif
75 #include <kdeversion.h>
77 #include "klauncher_cmds.h"
79 #ifdef Q_WS_X11
80 #include <X11/Xlib.h>
81 #include <X11/Xatom.h>
82 #include <fixx11h.h>
83 #include <kstartupinfo.h>
84 #endif
86 #if KDE_IS_VERSION( 3, 90, 0 )
87 #ifdef __GNUC__
88 #warning Check if Linux OOM-killer still sucks and if yes, forwardport revision 579164 and following fixes.
89 #endif
90 #endif
92 extern char **environ;
94 #ifdef Q_WS_X11
95 static int X11fd = -1;
96 static Display *X11display = 0;
97 static int X11_startup_notify_fd = -1;
98 static Display *X11_startup_notify_display = 0;
99 #endif
100 static KComponentData *s_instance = 0;
101 #define MAX_SOCK_FILE 255
102 static char sock_file[MAX_SOCK_FILE];
103 //static char sock_file_old[MAX_SOCK_FILE];
105 #ifdef Q_WS_X11
106 #define DISPLAY "DISPLAY"
107 #elif defined(Q_WS_QWS)
108 #define DISPLAY "QWS_DISPLAY"
109 #elif defined(Q_WS_MACX)
110 #define DISPLAY "MAC_DISPLAY"
111 #elif defined(Q_WS_WIN)
112 #define DISPLAY "WIN_DISPLAY"
113 #else
114 #error Use QT/X11 or QT/Embedded
115 #endif
117 /* Group data */
118 static struct {
119 int maxname;
120 int fd[2];
121 int launcher[2]; /* socket pair for launcher communication */
122 int deadpipe[2]; /* pipe used to detect dead children */
123 int initpipe[2];
124 int wrapper; /* socket for wrapper communication */
125 int wrapper_old; /* old socket for wrapper communication */
126 int accepted_fd; /* socket accepted and that must be closed in the child process */
127 char result;
128 int exit_status;
129 pid_t fork;
130 pid_t launcher_pid;
131 pid_t kded_pid;
132 pid_t my_pid;
133 int n;
134 char **argv;
135 int (*func)(int, char *[]);
136 int (*launcher_func)(int);
137 bool debug_wait;
138 QByteArray errorMsg;
139 bool launcher_ok;
140 bool suicide;
141 } d;
143 struct child
145 pid_t pid;
146 int sock; /* fd to write message when child is dead*/
147 struct child *next;
150 static struct child *children;
152 #ifdef Q_WS_X11
153 extern "C" {
154 int kdeinit_xio_errhandler( Display * );
155 int kdeinit_x_errhandler( Display *, XErrorEvent *err );
157 #endif
159 /* These are to link libkparts even if 'smart' linker is used */
160 #include <kparts/plugin.h>
161 extern "C" KParts::Plugin* _kinit_init_kparts() { return new KParts::Plugin(); }
162 /* These are to link libkio even if 'smart' linker is used */
163 #include <kio/authinfo.h>
164 extern "C" KIO::AuthInfo* _kioslave_init_kio() { return new KIO::AuthInfo(); }
167 * Clean up the file descriptor table by closing all file descriptors
168 * that are still open.
170 * This function is called very early in the main() function, so that
171 * we don't leak anything that was leaked to us.
173 static void cleanup_fds()
175 for (int fd = 3; fd < FD_SETSIZE; ++fd)
176 close(fd);
180 * Close fd's which are only useful for the parent process.
181 * Restore default signal handlers.
183 static void close_fds()
185 if (d.deadpipe[0] != -1)
187 close(d.deadpipe[0]);
188 d.deadpipe[0] = -1;
191 if (d.deadpipe[1] != -1)
193 close(d.deadpipe[1]);
194 d.deadpipe[1] = -1;
197 if (d.initpipe[0] != -1)
199 close(d.initpipe[0]);
200 d.initpipe[0] = -1;
203 if (d.initpipe[1] != -1)
205 close(d.initpipe[1]);
206 d.initpipe[1] = -1;
209 if (d.launcher_pid)
211 close(d.launcher[0]);
212 d.launcher_pid = 0;
214 if (d.wrapper != -1)
216 close(d.wrapper);
217 d.wrapper = -1;
219 if (d.wrapper_old != -1)
221 close(d.wrapper_old);
222 d.wrapper_old = -1;
224 if (d.accepted_fd != -1)
226 close(d.accepted_fd);
227 d.accepted_fd = -1;
229 #ifdef Q_WS_X11
230 if (X11fd >= 0)
232 close(X11fd);
233 X11fd = -1;
235 if (X11_startup_notify_fd >= 0 && X11_startup_notify_fd != X11fd )
237 close(X11_startup_notify_fd);
238 X11_startup_notify_fd = -1;
240 #endif
242 KDE_signal(SIGCHLD, SIG_DFL);
243 KDE_signal(SIGPIPE, SIG_DFL);
246 /* Notify wrapper program that the child it started has finished. */
247 static void child_died(pid_t exit_pid, int exit_status)
249 struct child *child = children;
250 struct child *prev = NULL;
252 while (child)
254 if (child->pid == exit_pid)
256 /* Send a message with the return value of the child on the control socket */
257 klauncher_header request_header;
258 long request_data[2];
259 request_header.cmd = LAUNCHER_DIED;
260 request_header.arg_length = sizeof(long) * 2;
261 request_data[0] = exit_pid;
262 request_data[1] = exit_status;
263 write(child->sock, &request_header, sizeof(request_header));
264 write(child->sock, request_data, request_header.arg_length);
265 close(child->sock);
267 if (prev)
269 prev->next = child->next;
271 else
273 child = NULL;
275 free(child);
276 return;
279 prev = child;
280 child = child->next;
285 static void exitWithErrorMsg(const QString &errorMsg)
287 fprintf( stderr, "%s\n", errorMsg.toLocal8Bit().data() );
288 QByteArray utf8ErrorMsg = errorMsg.toUtf8();
289 d.result = 3; // Error with msg
290 write(d.fd[1], &d.result, 1);
291 int l = utf8ErrorMsg.length();
292 write(d.fd[1], &l, sizeof(int));
293 write(d.fd[1], utf8ErrorMsg.data(), l);
294 close(d.fd[1]);
295 exit(255);
298 static void setup_tty( const char* tty )
300 if( tty == NULL || *tty == '\0' )
301 return;
302 int fd = KDE_open( tty, O_WRONLY );
303 if( fd < 0 )
305 perror( "kdeinit4: could not open() tty" );
306 return;
308 if( dup2( fd, STDOUT_FILENO ) < 0 )
310 perror( "kdeinit4: could not dup2() tty" );
311 close( fd );
312 return;
314 if( dup2( fd, STDERR_FILENO ) < 0 )
316 perror( "kdeinit4: could not dup2() tty" );
317 close( fd );
318 return;
320 close( fd );
323 // from kdecore/netwm.cpp
324 static int get_current_desktop( Display* disp )
326 int desktop = 0; // no desktop by default
327 #ifdef Q_WS_X11 // Only X11 supports multiple desktops
328 Atom net_current_desktop = XInternAtom( disp, "_NET_CURRENT_DESKTOP", False );
329 Atom type_ret;
330 int format_ret;
331 unsigned char *data_ret;
332 unsigned long nitems_ret, unused;
333 if( XGetWindowProperty( disp, DefaultRootWindow( disp ), net_current_desktop,
334 0l, 1l, False, XA_CARDINAL, &type_ret, &format_ret, &nitems_ret, &unused, &data_ret )
335 == Success)
337 if (type_ret == XA_CARDINAL && format_ret == 32 && nitems_ret == 1)
338 desktop = *((long *) data_ret) + 1;
339 if (data_ret)
340 XFree ((char*) data_ret);
342 #endif
343 return desktop;
346 // var has to be e.g. "DISPLAY=", i.e. with =
347 const char* get_env_var( const char* var, int envc, const char* envs )
349 if( envc > 0 )
350 { // get the var from envs
351 const char* env_l = envs;
352 int ln = strlen( var );
353 for (int i = 0; i < envc; i++)
355 if( strncmp( env_l, var, ln ) == 0 )
356 return env_l + ln;
357 while(*env_l != 0) env_l++;
358 env_l++;
361 return NULL;
364 #ifdef Q_WS_X11
365 static void init_startup_info( KStartupInfoId& id, const char* bin,
366 int envc, const char* envs )
368 const char* dpy = get_env_var( DISPLAY"=", envc, envs );
369 // this may be called in a child, so it can't use display open using X11display
370 // also needed for multihead
371 X11_startup_notify_display = XOpenDisplay( dpy );
372 if( X11_startup_notify_display == NULL )
373 return;
374 X11_startup_notify_fd = XConnectionNumber( X11_startup_notify_display );
375 KStartupInfoData data;
376 int desktop = get_current_desktop( X11_startup_notify_display );
377 data.setDesktop( desktop );
378 data.setBin( bin );
379 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
380 XFlush( X11_startup_notify_display );
383 static void complete_startup_info( KStartupInfoId& id, pid_t pid )
385 if( X11_startup_notify_display == NULL )
386 return;
387 if( pid == 0 ) // failure
388 KStartupInfo::sendFinishX( X11_startup_notify_display, id );
389 else
391 KStartupInfoData data;
392 data.addPid( pid );
393 data.setHostname();
394 KStartupInfo::sendChangeX( X11_startup_notify_display, id, data );
396 XCloseDisplay( X11_startup_notify_display );
397 X11_startup_notify_display = NULL;
398 X11_startup_notify_fd = -1;
400 #endif
402 QByteArray execpath_avoid_loops( const QByteArray& exec, int envc, const char* envs, bool avoid_loops )
404 QStringList paths;
405 if( envc > 0 ) /* use the passed environment */
407 const char* path = get_env_var( "PATH=", envc, envs );
408 if( path != NULL )
409 paths = QString(path).split( QRegExp( "[:\b]" ));
411 else
412 paths = QString::fromLocal8Bit( qgetenv("PATH") ).split( QRegExp( "[:\b]" ), QString::KeepEmptyParts );
413 QByteArray execpath = QFile::encodeName(
414 s_instance->dirs()->findExe( exec, paths.join( QLatin1String( ":" ))));
415 if( avoid_loops && !execpath.isEmpty())
417 int pos = execpath.lastIndexOf( '/' );
418 QString bin_path = execpath.left( pos );
419 for( QStringList::Iterator it = paths.begin();
420 it != paths.end();
421 ++it )
422 if( ( *it ) == bin_path || ( *it ) == bin_path + '/' )
424 paths.erase( it );
425 break; // -->
427 execpath = QFile::encodeName(
428 s_instance->dirs()->findExe( exec, paths.join( QString( ":" ))));
430 return execpath;
433 static pid_t launch(int argc, const char *_name, const char *args,
434 const char *cwd=0, int envc=0, const char *envs=0,
435 bool reset_env = false,
436 const char *tty=0, bool avoid_loops = false,
437 const char* startup_id_str = "0" )
439 int launcher = 0;
440 QByteArray lib;
441 QByteArray name;
442 QByteArray exec;
444 if (strcmp(_name, "klauncher") == 0) {
445 /* klauncher is launched in a special way:
446 * It has a communication socket on LAUNCHER_FD
448 if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, d.launcher))
450 perror("kdeinit4: socketpair() failed!\n");
451 exit(255);
453 launcher = 1;
456 QByteArray libpath;
457 QByteArray execpath;
458 if (_name[0] != '/')
460 lib = name = _name;
461 exec = name;
462 libpath = QFile::encodeName(KLibLoader::findLibrary(lib.constData(), *s_instance));
463 execpath = execpath_avoid_loops( exec, envc, envs, avoid_loops );
465 else
467 lib = _name;
468 name = _name;
469 name = name.mid( name.lastIndexOf('/') + 1);
470 exec = _name;
471 if (lib.endsWith(".la"))
472 libpath = lib;
473 else
474 execpath = exec;
476 fprintf(stderr,"kdeinit4: preparing to launch %s\n", execpath.constData());
477 if (!args)
479 argc = 1;
482 if (0 > pipe(d.fd))
484 perror("kdeinit4: pipe() failed!\n");
485 d.result = 3;
486 d.errorMsg = i18n("Unable to start new process.\n"
487 "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.").toUtf8();
488 d.fork = 0;
489 return d.fork;
492 #ifdef Q_WS_X11
493 KStartupInfoId startup_id;
494 startup_id.initId( startup_id_str );
495 if( !startup_id.none())
496 init_startup_info( startup_id, name, envc, envs );
497 #endif
499 d.errorMsg = 0;
500 d.fork = fork();
501 switch(d.fork) {
502 case -1:
503 perror("kdeinit4: fork() failed!\n");
504 d.result = 3;
505 d.errorMsg = i18n("Unable to create new process.\n"
506 "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.").toUtf8();
507 close(d.fd[0]);
508 close(d.fd[1]);
509 d.fork = 0;
510 break;
511 case 0:
513 /** Child **/
514 close(d.fd[0]);
515 close_fds();
516 if (launcher)
518 if (d.fd[1] == LAUNCHER_FD)
520 d.fd[1] = dup(d.fd[1]); // Evacuate from LAUNCHER_FD
522 if (d.launcher[1] != LAUNCHER_FD)
524 dup2( d.launcher[1], LAUNCHER_FD); // Make sure the socket has fd LAUNCHER_FD
525 close( d.launcher[1] );
527 close( d.launcher[0] );
530 if (cwd && *cwd)
531 chdir(cwd);
532 else {
533 const QByteArray docPath = QFile::encodeName(KGlobalSettings::documentPath());
534 chdir(docPath.constData());
537 if( reset_env ) // KWRAPPER/SHELL
540 QList<QByteArray> unset_envs;
541 for( int tmp_env_count = 0;
542 environ[tmp_env_count];
543 tmp_env_count++)
544 unset_envs.append( environ[ tmp_env_count ] );
545 foreach(const QByteArray &tmp, unset_envs)
547 int pos = tmp.indexOf( '=' );
548 if( pos >= 0 )
549 unsetenv( tmp.left( pos ));
553 for (int i = 0; i < envc; i++)
555 putenv((char *)envs);
556 while(*envs != 0) envs++;
557 envs++;
560 #ifdef Q_WS_X11
561 if( startup_id.none())
562 KStartupInfo::resetStartupEnv();
563 else
564 startup_id.setupStartupEnv();
565 #endif
567 int r;
568 QByteArray procTitle;
569 d.argv = (char **) malloc(sizeof(char *) * (argc+1));
570 d.argv[0] = (char *) _name;
571 #ifdef Q_WS_MAC
572 QString argvexe = s_instance->dirs()->findExe(QString::fromLatin1(d.argv[0]));
573 if (!argvexe.isEmpty()) {
574 QByteArray cstr = argvexe.toLocal8Bit();
575 kDebug(7016) << "kdeinit4: launch() setting argv: " << cstr.data();
576 d.argv[0] = strdup(cstr.data());
578 #endif
579 for (int i = 1; i < argc; i++)
581 d.argv[i] = (char *) args;
582 procTitle += ' ';
583 procTitle += (char *) args;
584 while(*args != 0) args++;
585 args++;
587 d.argv[argc] = 0;
589 /** Give the process a new name **/
590 #ifdef Q_OS_LINUX
591 /* set the process name, so that killall works like intended */
592 r = prctl(PR_SET_NAME, (unsigned long) name.data(), 0, 0, 0);
593 if ( r == 0 )
594 proctitle_set( "%s [kdeinit]%s", name.data(), procTitle.data() ? procTitle.data() : "" );
595 else
596 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
597 #else
598 proctitle_set( "kdeinit4: %s%s", name.data(), procTitle.data() ? procTitle.data() : "" );
599 #endif
602 if (libpath.isEmpty() && execpath.isEmpty())
604 QString errorMsg = i18n("Could not find '%1' executable.", QFile::decodeName(_name));
605 exitWithErrorMsg(errorMsg);
609 if ( !qgetenv("KDE_IS_PRELINKED").isEmpty() && !execpath.isEmpty() && !launcher)
610 libpath.truncate(0);
612 QLibrary l(libpath);
614 if ( !libpath.isEmpty() )
616 if (!l.load() || !l.isLoaded() )
618 QString ltdlError (l.errorString());
619 if (execpath.isEmpty())
621 // Error
622 QString errorMsg = i18n("Could not open library '%1'.\n%2", QFile::decodeName(libpath), ltdlError);
623 exitWithErrorMsg(errorMsg);
625 else
627 // Print warning
628 fprintf(stderr, "Could not open library %s: %s\n", lib.data(),
629 qPrintable(ltdlError) );
633 if (!l.isLoaded())
635 d.result = 2; // Try execing
636 write(d.fd[1], &d.result, 1);
638 // We set the close on exec flag.
639 // Closing of d.fd[1] indicates that the execvp succeeded!
640 fcntl(d.fd[1], F_SETFD, FD_CLOEXEC);
642 setup_tty( tty );
644 QByteArray executable = execpath.data();
645 #ifdef Q_WS_MAC
646 QString bundlepath = s_instance->dirs()->findExe( execpath.data() );
647 if (!bundlepath.isEmpty())
648 executable = QFile::encodeName(bundlepath);
649 #endif
651 if (!executable.isEmpty())
652 execvp(executable, d.argv);
654 d.result = 1; // Error
655 write(d.fd[1], &d.result, 1);
656 close(d.fd[1]);
657 exit(255);
660 void * sym = l.resolve( "kdeinitmain");
661 if (!sym )
663 sym = l.resolve( "kdemain" );
664 if ( !sym )
666 QString ltdlError = l.errorString();
667 fprintf(stderr, "Could not find kdemain: %s\n", qPrintable(ltdlError) );
668 QString errorMsg = i18n("Could not find 'kdemain' in '%1'.\n%2",
669 QLatin1String(libpath), ltdlError);
670 exitWithErrorMsg(errorMsg);
674 d.result = 0; // Success
675 write(d.fd[1], &d.result, 1);
676 close(d.fd[1]);
678 d.func = (int (*)(int, char *[])) sym;
679 if (d.debug_wait)
681 fprintf(stderr, "kdeinit4: Suspending process\n"
682 "kdeinit4: 'gdb kdeinit4 %d' to debug\n"
683 "kdeinit4: 'kill -SIGCONT %d' to continue\n",
684 getpid(), getpid());
685 kill(getpid(), SIGSTOP);
687 else
689 setup_tty( tty );
692 exit( d.func(argc, d.argv)); /* Launch! */
694 break;
696 default:
697 /** Parent **/
698 close(d.fd[1]);
699 if (launcher)
701 close(d.launcher[1]);
702 d.launcher_pid = d.fork;
704 bool exec = false;
705 for(;;)
707 d.n = read(d.fd[0], &d.result, 1);
708 if (d.n == 1)
710 if (d.result == 2)
712 #ifndef NDEBUG
713 //fprintf(stderr, "kdeinit4: no kdeinit module, trying exec....\n");
714 #endif
715 exec = true;
716 continue;
718 if (d.result == 3)
720 int l = 0;
721 d.n = read(d.fd[0], &l, sizeof(int));
722 if (d.n == sizeof(int))
724 QByteArray tmp;
725 tmp.resize(l+1);
726 d.n = read(d.fd[0], tmp.data(), l);
727 tmp[l] = 0;
728 if (d.n == l)
729 d.errorMsg = tmp;
732 // Finished
733 break;
735 if (d.n == -1)
737 if (errno == ECHILD) { // a child died.
738 continue;
740 if (errno == EINTR || errno == EAGAIN) { // interrupted or more to read
741 continue;
744 if (exec)
746 d.result = 0;
747 break;
749 if (d.n == 0)
751 fprintf(stderr,"kdeinit4: (%s %s) Pipe closed unexpectedly", name.constData(), execpath.constData());
752 perror("kdeinit4: Pipe closed unexpectedly");
753 d.result = 1; // Error
754 break;
756 perror("kdeinit4: Error reading from pipe");
757 d.result = 1; // Error
758 break;
760 close(d.fd[0]);
761 if (launcher && (d.result == 0))
763 // Trader launched successful
764 d.launcher_pid = d.fork;
767 #ifdef Q_WS_X11
768 if( !startup_id.none())
770 if( d.fork && d.result == 0 ) // launched successfully
771 complete_startup_info( startup_id, d.fork );
772 else // failure, cancel ASN
773 complete_startup_info( startup_id, 0 );
775 #endif
776 return d.fork;
779 static void sig_child_handler(int)
782 * Write into the pipe of death.
783 * This way we are sure that we return from the select()
785 * A signal itself causes select to return as well, but
786 * this creates a race-condition in case the signal arrives
787 * just before we enter the select.
789 char c = 0;
790 write(d.deadpipe[1], &c, 1);
793 static void init_signals()
795 struct sigaction act;
796 long options;
798 if (pipe(d.deadpipe) != 0)
800 perror("kdeinit4: Aborting. Can not create pipe: ");
801 exit(255);
804 options = fcntl(d.deadpipe[0], F_GETFL);
805 if (options == -1)
807 perror("kdeinit4: Aborting. Can not make pipe non-blocking: ");
808 exit(255);
811 if (fcntl(d.deadpipe[0], F_SETFL, options | O_NONBLOCK) == -1)
813 perror("kdeinit4: Aborting. Can not make pipe non-blocking: ");
814 exit(255);
818 * A SIGCHLD handler is installed which sends a byte into the
819 * pipe of death. This is to ensure that a dying child causes
820 * an exit from select().
822 act.sa_handler=sig_child_handler;
823 sigemptyset(&(act.sa_mask));
824 sigaddset(&(act.sa_mask), SIGCHLD);
825 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
826 act.sa_flags = SA_NOCLDSTOP;
828 // CC: take care of SunOS which automatically restarts interrupted system
829 // calls (and thus does not have SA_RESTART)
831 #ifdef SA_RESTART
832 act.sa_flags |= SA_RESTART;
833 #endif
834 sigaction( SIGCHLD, &act, 0L);
836 act.sa_handler=SIG_IGN;
837 sigemptyset(&(act.sa_mask));
838 sigaddset(&(act.sa_mask), SIGPIPE);
839 sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0L);
840 act.sa_flags = 0;
841 sigaction( SIGPIPE, &act, 0L);
844 static void init_kdeinit_socket()
846 struct sockaddr_un sa;
847 //struct sockaddr_un sa_old;
848 kde_socklen_t socklen;
849 long options;
850 const QByteArray home_dir = qgetenv("HOME");
851 int max_tries = 10;
852 if (home_dir.isEmpty())
854 fprintf(stderr, "kdeinit4: Aborting. $HOME not set!");
855 exit(255);
857 chdir(home_dir);
860 QByteArray path = home_dir;
861 QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
862 if (access(path.data(), R_OK|W_OK))
864 if (errno == ENOENT)
866 fprintf(stderr, "kdeinit4: Aborting. $HOME directory (%s) does not exist.\n", path.data());
867 exit(255);
869 else if (readOnly.isEmpty())
871 fprintf(stderr, "kdeinit4: Aborting. No write access to $HOME directory (%s).\n", path.data());
872 exit(255);
875 #if 0 // obsolete in kde4. Should we check writing to another file instead?
876 path = qgetenv("ICEAUTHORITY");
877 if (path.isEmpty())
879 path = home_dir;
880 path += "/.ICEauthority";
882 if (access(path.data(), R_OK|W_OK) && (errno != ENOENT))
884 fprintf(stderr, "kdeinit4: Aborting. No write access to '%s'.\n", path.data());
885 exit(255);
887 #endif
890 /** Test if socket file is already present
891 * note that access() resolves symlinks, and so we check the actual
892 * socket file if it exists
894 if (access(sock_file, W_OK) == 0)
896 int s;
897 struct sockaddr_un server;
899 // fprintf(stderr, "kdeinit4: Warning, socket_file already exists!\n");
901 * create the socket stream
903 s = socket(PF_UNIX, SOCK_STREAM, 0);
904 if (s < 0)
906 perror("socket() failed: ");
907 exit(255);
909 server.sun_family = AF_UNIX;
910 strcpy(server.sun_path, sock_file);
911 socklen = sizeof(server);
913 if(connect(s, (struct sockaddr *)&server, socklen) == 0)
915 fprintf(stderr, "kdeinit4: Shutting down running client.\n");
916 klauncher_header request_header;
917 request_header.cmd = LAUNCHER_TERMINATE_KDEINIT;
918 request_header.arg_length = 0;
919 write(s, &request_header, sizeof(request_header));
920 sleep(1); // Give it some time
922 close(s);
925 /** Delete any stale socket file (and symlink) **/
926 unlink(sock_file);
927 // unlink(sock_file_old);
929 /** create socket **/
930 d.wrapper = socket(PF_UNIX, SOCK_STREAM, 0);
931 if (d.wrapper < 0)
933 perror("kdeinit4: Aborting. socket() failed: ");
934 exit(255);
937 options = fcntl(d.wrapper, F_GETFL);
938 if (options == -1)
940 perror("kdeinit4: Aborting. Can not make socket non-blocking: ");
941 close(d.wrapper);
942 exit(255);
945 if (fcntl(d.wrapper, F_SETFL, options | O_NONBLOCK) == -1)
947 perror("kdeinit4: Aborting. Can not make socket non-blocking: ");
948 close(d.wrapper);
949 exit(255);
952 if (fcntl(d.wrapper, F_SETFD, FD_CLOEXEC) == -1)
954 perror("kdeinit4: Aborting. Can not make socket close-on-execute: ");
955 close(d.wrapper);
956 exit(255);
959 while (1) {
960 /** bind it **/
961 socklen = sizeof(sa);
962 memset(&sa, 0, socklen);
963 sa.sun_family = AF_UNIX;
964 strcpy(sa.sun_path, sock_file);
965 if(bind(d.wrapper, (struct sockaddr *)&sa, socklen) != 0)
967 if (max_tries == 0) {
968 perror("kdeinit4: Aborting. bind() failed: ");
969 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file);
970 close(d.wrapper);
971 exit(255);
973 max_tries--;
974 } else
975 break;
978 /** set permissions **/
979 if (chmod(sock_file, 0600) != 0)
981 perror("kdeinit4: Aborting. Can not set permissions on socket: ");
982 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
983 unlink(sock_file);
984 close(d.wrapper);
985 exit(255);
988 if(listen(d.wrapper, SOMAXCONN) < 0)
990 perror("kdeinit4: Aborting. listen() failed: ");
991 unlink(sock_file);
992 close(d.wrapper);
993 exit(255);
996 #if 0
997 /** create compatibility socket **/
998 d.wrapper_old = socket(PF_UNIX, SOCK_STREAM, 0);
999 if (d.wrapper_old < 0)
1001 // perror("kdeinit4: Aborting. socket() failed: ");
1002 return;
1005 options = fcntl(d.wrapper_old, F_GETFL);
1006 if (options == -1)
1008 // perror("kdeinit4: Aborting. Can't make socket non-blocking: ");
1009 close(d.wrapper_old);
1010 d.wrapper_old = -1;
1011 return;
1014 if (fcntl(d.wrapper_old, F_SETFL, options | O_NONBLOCK) == -1)
1016 // perror("kdeinit4: Aborting. Can't make socket non-blocking: ");
1017 close(d.wrapper_old);
1018 d.wrapper_old = -1;
1019 return;
1022 if (fcntl(d.wrapper, F_SETFD, FD_CLOEXEC) == -1)
1024 //perror("kdeinit4: Aborting. Can't make socket close-on-execute: ");
1025 close(d.wrapper);
1026 d.wrapper_old = -1;
1027 return;
1030 max_tries = 10;
1031 while (1) {
1032 /** bind it **/
1033 socklen = sizeof(sa_old);
1034 memset(&sa_old, 0, socklen);
1035 sa_old.sun_family = AF_UNIX;
1036 strcpy(sa_old.sun_path, sock_file_old);
1037 if(bind(d.wrapper_old, (struct sockaddr *)&sa_old, socklen) != 0)
1039 if (max_tries == 0) {
1040 // perror("kdeinit4: Aborting. bind() failed: ");
1041 fprintf(stderr, "Could not bind to socket '%s'\n", sock_file_old);
1042 close(d.wrapper_old);
1043 d.wrapper_old = -1;
1044 return;
1046 max_tries--;
1047 } else
1048 break;
1051 /** set permissions **/
1052 if (chmod(sock_file_old, 0600) != 0)
1054 fprintf(stderr, "Wrong permissions of socket '%s'\n", sock_file);
1055 unlink(sock_file_old);
1056 close(d.wrapper_old);
1057 d.wrapper_old = -1;
1058 return;
1061 if(listen(d.wrapper_old, SOMAXCONN) < 0)
1063 // perror("kdeinit4: Aborting. listen() failed: ");
1064 unlink(sock_file_old);
1065 close(d.wrapper_old);
1066 d.wrapper_old = -1;
1068 #endif
1072 * Read 'len' bytes from 'sock' into buffer.
1073 * returns 0 on success, -1 on failure.
1075 static int read_socket(int sock, char *buffer, int len)
1077 ssize_t result;
1078 int bytes_left = len;
1079 while ( bytes_left > 0)
1081 result = read(sock, buffer, bytes_left);
1082 if (result > 0)
1084 buffer += result;
1085 bytes_left -= result;
1087 else if (result == 0)
1088 return -1;
1089 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
1090 return -1;
1092 return 0;
1095 static void launcher_died()
1097 if (!d.launcher_ok)
1099 /* This is bad. */
1100 fprintf(stderr, "kdeinit4: Communication error with launcher. Exiting!\n");
1101 ::exit(255);
1102 return;
1105 // KLauncher died... restart
1106 #ifndef NDEBUG
1107 fprintf(stderr, "kdeinit4: KLauncher died unexpectedly.\n");
1108 #endif
1109 // Make sure it's really dead.
1110 if (d.launcher_pid)
1112 kill(d.launcher_pid, SIGKILL);
1113 sleep(1); // Give it some time
1116 d.launcher_ok = false;
1117 d.launcher_pid = 0;
1118 close(d.launcher[0]);
1119 d.launcher[0] = -1;
1121 pid_t pid = launch( 1, "klauncher", 0 );
1122 #ifndef NDEBUG
1123 fprintf(stderr, "kdeinit4: Relaunching KLauncher, pid = %ld result = %d\n", (long) pid, d.result);
1124 #endif
1127 static void handle_launcher_request(int sock = -1)
1129 bool launcher = false;
1130 if (sock < 0)
1132 sock = d.launcher[0];
1133 launcher = true;
1135 else
1137 d.accepted_fd = sock;
1140 klauncher_header request_header;
1141 char *request_data = 0L;
1142 int result = read_socket(sock, (char *) &request_header, sizeof(request_header));
1143 if (result != 0)
1145 if (launcher)
1146 launcher_died();
1147 return;
1150 if ( request_header.arg_length != 0 )
1152 request_data = (char *) malloc(request_header.arg_length);
1154 result = read_socket(sock, request_data, request_header.arg_length);
1155 if (result != 0)
1157 if (launcher)
1158 launcher_died();
1159 free(request_data);
1160 return;
1164 if (request_header.cmd == LAUNCHER_OK)
1166 d.launcher_ok = true;
1168 else if (request_header.arg_length &&
1169 ((request_header.cmd == LAUNCHER_EXEC) ||
1170 (request_header.cmd == LAUNCHER_EXT_EXEC) ||
1171 (request_header.cmd == LAUNCHER_SHELL ) ||
1172 (request_header.cmd == LAUNCHER_KWRAPPER) ||
1173 (request_header.cmd == LAUNCHER_EXEC_NEW)))
1175 pid_t pid;
1176 klauncher_header response_header;
1177 long response_data;
1178 long l;
1179 memcpy( &l, request_data, sizeof( long ));
1180 int argc = l;
1181 const char *name = request_data + sizeof(long);
1182 const char *args = name + strlen(name) + 1;
1183 const char *cwd = 0;
1184 int envc = 0;
1185 const char *envs = 0;
1186 const char *tty = 0;
1187 int avoid_loops = 0;
1188 const char *startup_id_str = "0";
1190 #ifndef NDEBUG
1191 fprintf(stderr, "kdeinit4: Got %s '%s' from %s.\n",
1192 (request_header.cmd == LAUNCHER_EXEC ? "EXEC" :
1193 (request_header.cmd == LAUNCHER_EXT_EXEC ? "EXT_EXEC" :
1194 (request_header.cmd == LAUNCHER_EXEC_NEW ? "EXEC_NEW" :
1195 (request_header.cmd == LAUNCHER_SHELL ? "SHELL" : "KWRAPPER" )))),
1196 name, launcher ? "launcher" : "socket" );
1197 #endif
1199 const char *arg_n = args;
1200 for(int i = 1; i < argc; i++)
1202 arg_n = arg_n + strlen(arg_n) + 1;
1205 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER )
1207 // Shell or kwrapper
1208 cwd = arg_n; arg_n += strlen(cwd) + 1;
1210 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
1211 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
1213 memcpy( &l, arg_n, sizeof( long ));
1214 envc = l;
1215 arg_n += sizeof(long);
1216 envs = arg_n;
1217 for(int i = 0; i < envc; i++)
1219 arg_n = arg_n + strlen(arg_n) + 1;
1221 if( request_header.cmd == LAUNCHER_KWRAPPER )
1223 tty = arg_n;
1224 arg_n += strlen( tty ) + 1;
1228 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
1229 || request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW )
1231 memcpy( &l, arg_n, sizeof( long ));
1232 avoid_loops = l;
1233 arg_n += sizeof( long );
1236 if( request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER
1237 || request_header.cmd == LAUNCHER_EXT_EXEC )
1239 startup_id_str = arg_n;
1240 arg_n += strlen( startup_id_str ) + 1;
1243 if ((request_header.arg_length > (arg_n - request_data)) &&
1244 (request_header.cmd == LAUNCHER_EXT_EXEC || request_header.cmd == LAUNCHER_EXEC_NEW ))
1246 // Optional cwd
1247 cwd = arg_n; arg_n += strlen(cwd) + 1;
1250 if ((arg_n - request_data) != request_header.arg_length)
1252 #ifndef NDEBUG
1253 fprintf(stderr, "kdeinit4: EXEC request has invalid format.\n");
1254 #endif
1255 free(request_data);
1256 d.debug_wait = false;
1257 return;
1260 // support for the old a bit broken way of setting DISPLAY for multihead
1261 QByteArray olddisplay = qgetenv(DISPLAY);
1262 QByteArray kdedisplay = qgetenv("KDE_DISPLAY");
1263 bool reset_display = (! olddisplay.isEmpty() &&
1264 ! kdedisplay.isEmpty() &&
1265 olddisplay != kdedisplay);
1267 if (reset_display)
1268 setenv(DISPLAY, kdedisplay, true);
1270 pid = launch( argc, name, args, cwd, envc, envs,
1271 request_header.cmd == LAUNCHER_SHELL || request_header.cmd == LAUNCHER_KWRAPPER,
1272 tty, avoid_loops, startup_id_str );
1274 if (reset_display) {
1275 unsetenv("KDE_DISPLAY");
1276 setenv(DISPLAY, olddisplay, true);
1279 if (pid && (d.result == 0))
1281 response_header.cmd = LAUNCHER_OK;
1282 response_header.arg_length = sizeof(response_data);
1283 response_data = pid;
1284 write(sock, &response_header, sizeof(response_header));
1285 write(sock, &response_data, response_header.arg_length);
1287 /* add new child to list */
1288 struct child *child = (struct child *) malloc(sizeof(struct child));
1289 child->pid = pid;
1290 child->sock = dup(sock);
1291 child->next = children;
1292 children = child;
1294 /* check child hasn't terminated already */
1295 if (kill(pid, 0))
1297 children = child->next;
1298 free(child);
1301 else
1303 int l = d.errorMsg.length();
1304 if (l) l++; // Include trailing null.
1305 response_header.cmd = LAUNCHER_ERROR;
1306 response_header.arg_length = l;
1307 write(sock, &response_header, sizeof(response_header));
1308 if (l)
1309 write(sock, d.errorMsg.data(), l);
1311 d.debug_wait = false;
1313 else if (request_header.arg_length && request_header.cmd == LAUNCHER_SETENV)
1315 const char *env_name;
1316 const char *env_value;
1317 env_name = request_data;
1318 env_value = env_name + strlen(env_name) + 1;
1320 #ifndef NDEBUG
1321 if (launcher)
1322 fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from klauncher.\n", env_name, env_value);
1323 else
1324 fprintf(stderr, "kdeinit4: Got SETENV '%s=%s' from socket.\n", env_name, env_value);
1325 #endif
1327 if ( request_header.arg_length !=
1328 (int) (strlen(env_name) + strlen(env_value) + 2))
1330 #ifndef NDEBUG
1331 fprintf(stderr, "kdeinit4: SETENV request has invalid format.\n");
1332 #endif
1333 free(request_data);
1334 return;
1336 setenv( env_name, env_value, 1);
1338 else if (request_header.cmd == LAUNCHER_TERMINATE_KDE)
1340 #ifndef NDEBUG
1341 fprintf(stderr,"kdeinit4: terminate KDE.\n");
1342 #endif
1343 #ifdef Q_WS_X11
1344 kdeinit_xio_errhandler( 0L );
1345 #endif
1347 else if (request_header.cmd == LAUNCHER_TERMINATE_KDEINIT)
1349 #ifndef NDEBUG
1350 fprintf(stderr,"kdeinit4: Killing kdeinit/klauncher.\n");
1351 #endif
1352 if (d.launcher_pid)
1353 kill(d.launcher_pid, SIGTERM);
1354 if (d.my_pid)
1355 kill(d.my_pid, SIGTERM);
1357 else if (request_header.cmd == LAUNCHER_DEBUG_WAIT)
1359 #ifndef NDEBUG
1360 fprintf(stderr,"kdeinit4: Debug wait activated.\n");
1361 #endif
1362 d.debug_wait = true;
1364 if (request_data)
1365 free(request_data);
1368 static void handle_requests(pid_t waitForPid)
1370 int max_sock = d.wrapper;
1371 if (d.wrapper_old > max_sock)
1372 max_sock = d.wrapper_old;
1373 if (d.launcher_pid && (d.launcher[0] > max_sock))
1374 max_sock = d.launcher[0];
1375 #ifdef Q_WS_X11
1376 if (X11fd > max_sock)
1377 max_sock = X11fd;
1378 #endif
1379 max_sock++;
1381 while(1)
1383 fd_set rd_set;
1384 fd_set wr_set;
1385 fd_set e_set;
1386 int result;
1387 pid_t exit_pid;
1388 int exit_status;
1389 char c;
1391 /* Flush the pipe of death */
1392 while( read(d.deadpipe[0], &c, 1) == 1);
1394 /* Handle dying children */
1395 do {
1396 exit_pid = waitpid(-1, &exit_status, WNOHANG);
1397 if (exit_pid > 0)
1399 #ifndef NDEBUG
1400 fprintf(stderr, "kdeinit4: PID %ld terminated.\n", (long) exit_pid);
1401 #endif
1402 if (waitForPid && (exit_pid == waitForPid))
1403 return;
1405 if( WIFEXITED( exit_status )) // fix process return value
1406 exit_status = WEXITSTATUS(exit_status);
1407 else if( WIFSIGNALED( exit_status ))
1408 exit_status = 128 + WTERMSIG( exit_status );
1409 child_died(exit_pid, exit_status);
1412 while( exit_pid > 0);
1414 /* Set up the next loop */
1415 d.accepted_fd = -1;
1417 FD_ZERO(&rd_set);
1418 FD_ZERO(&wr_set);
1419 FD_ZERO(&e_set);
1421 if (d.launcher_pid)
1423 FD_SET(d.launcher[0], &rd_set);
1425 FD_SET(d.wrapper, &rd_set);
1426 if (d.wrapper_old != -1)
1428 FD_SET(d.wrapper_old, &rd_set);
1430 FD_SET(d.deadpipe[0], &rd_set);
1431 #ifdef Q_WS_X11
1432 if(X11fd >= 0) FD_SET(X11fd, &rd_set);
1433 #endif
1435 result = select(max_sock, &rd_set, &wr_set, &e_set, 0);
1437 /* Handle wrapper request */
1438 if ((result > 0) && (FD_ISSET(d.wrapper, &rd_set)))
1440 struct sockaddr_un client;
1441 kde_socklen_t sClient = sizeof(client);
1442 int sock = accept(d.wrapper, (struct sockaddr *)&client, &sClient);
1443 if (sock >= 0)
1445 handle_launcher_request(sock);
1446 close(sock);
1449 if ((result > 0) && d.wrapper_old != -1 && (FD_ISSET(d.wrapper_old, &rd_set)))
1451 struct sockaddr_un client;
1452 kde_socklen_t sClient = sizeof(client);
1453 int sock = accept(d.wrapper_old, (struct sockaddr *)&client, &sClient);
1454 if (sock >= 0)
1456 handle_launcher_request(sock);
1457 close(sock);
1461 /* Handle launcher request */
1462 if ((result > 0) && (d.launcher_pid) && (FD_ISSET(d.launcher[0], &rd_set)))
1464 handle_launcher_request();
1465 if (waitForPid == d.launcher_pid)
1466 return;
1469 #ifdef Q_WS_X11
1470 /* Look for incoming X11 events */
1471 if((result > 0) && (X11fd >= 0))
1473 if(FD_ISSET(X11fd,&rd_set))
1475 if (X11display != 0) {
1476 XEvent event_return;
1477 while (XPending(X11display))
1478 XNextEvent(X11display, &event_return);
1482 #endif
1486 static void kdeinit_library_path()
1488 QStringList ltdl_library_path =
1489 QFile::decodeName(qgetenv("LTDL_LIBRARY_PATH")).split(':',QString::SkipEmptyParts);
1490 #ifdef Q_OS_DARWIN
1491 QStringList ld_library_path =
1492 QFile::decodeName(qgetenv("DYLD_LIBRARY_PATH")).split(':',QString::SkipEmptyParts);
1493 #else
1494 QStringList ld_library_path =
1495 QFile::decodeName(qgetenv("LD_LIBRARY_PATH")).split(':',QString::SkipEmptyParts);
1496 #endif
1498 QByteArray extra_path;
1499 QStringList candidates = s_instance->dirs()->resourceDirs("lib");
1500 for (QStringList::ConstIterator it = candidates.begin();
1501 it != candidates.end();
1502 ++it)
1504 QString d = *it;
1505 if (ltdl_library_path.contains(d))
1506 continue;
1507 if (ld_library_path.contains(d))
1508 continue;
1509 if (d[d.length()-1] == '/')
1511 d.truncate(d.length()-1);
1512 if (ltdl_library_path.contains(d))
1513 continue;
1514 if (ld_library_path.contains(d))
1515 continue;
1517 if ((d == "/lib") || (d == "/usr/lib"))
1518 continue;
1520 QByteArray dir = QFile::encodeName(d);
1522 if (access(dir, R_OK))
1523 continue;
1525 if ( !extra_path.isEmpty())
1526 extra_path += ':';
1527 extra_path += dir;
1530 // if (!extra_path.isEmpty())
1531 // lt_dlsetsearchpath(extra_path.data());
1533 QByteArray display = qgetenv(DISPLAY);
1534 if (display.isEmpty())
1536 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
1537 fprintf(stderr, "kdeinit4: Aborting. $"DISPLAY" is not set.\n");
1538 exit(255);
1539 #endif
1541 int i;
1542 if((i = display.lastIndexOf('.')) > display.lastIndexOf(':') && i >= 0)
1543 display.truncate(i);
1545 // Was kdeinit-display initially,
1546 // then at some point in KDE-3.x it became kdeinit_display_with_underscores
1547 // And for KDE4 it became kdeinit4_display_with_underscores, to avoid messing up the kde3 kdeinit.
1548 // Compat code needed just in case we need it later for something else.
1549 #if 0
1550 QByteArray socketName = QFile::encodeName(locateLocal("socket", QString("kdeinit-%1").arg(QLatin1String(display)), *s_instance));
1551 if (socketName.length() >= MAX_SOCK_FILE)
1553 fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
1554 fprintf(stderr, " '%s'\n", socketName.data());
1555 exit(255);
1557 strcpy(sock_file_old, socketName.data());
1558 #endif
1560 display.replace(':','_');
1561 // WARNING, if you change the socket name, adjust kwrapper too
1562 QByteArray socketName = QFile::encodeName(KStandardDirs::locateLocal("socket", QString("kdeinit4_%1").arg(QLatin1String(display)), *s_instance));
1563 if (socketName.length() >= MAX_SOCK_FILE)
1565 fprintf(stderr, "kdeinit4: Aborting. Socket name will be too long:\n");
1566 fprintf(stderr, " '%s'\n", socketName.data());
1567 exit(255);
1569 strcpy(sock_file, socketName.data());
1572 int kdeinit_xio_errhandler( Display *disp )
1574 // disp is 0L when KDE shuts down. We don't want those warnings then.
1576 if ( disp )
1577 qWarning( "kdeinit4: Fatal IO error: client killed" );
1579 if (sock_file[0])
1581 /** Delete any stale socket file **/
1582 unlink(sock_file);
1584 #if 0
1585 if (sock_file_old[0])
1587 /** Delete any stale socket file **/
1588 unlink(sock_file_old);
1590 #endif
1592 // Don't kill our children in suicide mode, they may still be in use
1593 if (d.suicide)
1595 if (d.launcher_pid)
1596 kill(d.launcher_pid, SIGTERM);
1597 if (d.kded_pid)
1598 kill(d.kded_pid, SIGTERM);
1599 exit( 0 );
1602 if ( disp )
1603 qWarning( "kdeinit4: sending SIGHUP to children." );
1605 /* this should remove all children we started */
1606 KDE_signal(SIGHUP, SIG_IGN);
1607 kill(0, SIGHUP);
1609 sleep(2);
1611 if ( disp )
1612 qWarning( "kdeinit4: sending SIGTERM to children." );
1614 /* and if they don't listen to us, this should work */
1615 KDE_signal(SIGTERM, SIG_IGN);
1616 kill(0, SIGTERM);
1618 if ( disp )
1619 qWarning( "kdeinit4: Exit." );
1621 exit( 0 );
1622 return 0;
1625 #ifdef Q_WS_X11
1626 int kdeinit_x_errhandler( Display *dpy, XErrorEvent *err )
1628 #ifndef NDEBUG
1629 char errstr[256];
1630 // kdeinit almost doesn't use X, and therefore there shouldn't be any X error
1631 XGetErrorText( dpy, err->error_code, errstr, 256 );
1632 fprintf(stderr, "kdeinit4: KDE detected X Error: %s %d\n"
1633 " Major opcode: %d\n"
1634 " Minor opcode: %d\n"
1635 " Resource id: 0x%lx\n",
1636 errstr, err->error_code, err->request_code, err->minor_code, err->resourceid );
1637 #else
1638 Q_UNUSED(dpy);
1639 Q_UNUSED(err);
1640 #endif
1641 return 0;
1643 #endif
1645 #ifdef Q_WS_X11
1646 // needs to be done sooner than initXconnection() because of also opening
1647 // another X connection for startup notification purposes
1648 static void setupX()
1650 XSetIOErrorHandler(kdeinit_xio_errhandler);
1651 XSetErrorHandler(kdeinit_x_errhandler);
1654 // Borrowed from kdebase/kaudio/kaudioserver.cpp
1655 static int initXconnection()
1657 X11display = XOpenDisplay(NULL);
1658 if ( X11display != 0 ) {
1659 XCreateSimpleWindow(X11display, DefaultRootWindow(X11display), 0,0,1,1, \
1661 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)),
1662 BlackPixelOfScreen(DefaultScreenOfDisplay(X11display)) );
1663 #ifndef NDEBUG
1664 fprintf(stderr, "kdeinit4: opened connection to %s\n", DisplayString(X11display));
1665 #endif
1666 int fd = XConnectionNumber( X11display );
1667 int on = 1;
1668 (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, (int) sizeof(on));
1669 return fd;
1670 } else
1671 fprintf(stderr, "kdeinit4: Can not connect to the X Server.\n" \
1672 "kdeinit4: Might not terminate at end of session.\n");
1674 return -1;
1676 #endif
1678 #ifdef __KCC
1679 /* One of my horrible hacks. KCC includes in each "main" function a call
1680 to _main(), which is provided by the C++ runtime system. It is
1681 responsible for calling constructors for some static objects. That must
1682 be done only once, so _main() is guarded against multiple calls.
1683 For unknown reasons the designers of KAI's libKCC decided it would be
1684 a good idea to actually abort() when it's called multiple times, instead
1685 of ignoring further calls. This breaks our mechanism of KLM's, because
1686 most KLM's have a main() function which is called from us.
1687 The "solution" is to simply define our own _main(), which ignores multiple
1688 calls, which is easy, and which does the same work as KAI'c _main(),
1689 which is difficult. Currently (KAI 4.0f) it only calls __call_ctors(void)
1690 (a C++ function), but if that changes we need to change our's too.
1691 (matz) */
1693 Those 'unknown reasons' are C++ standard forbidding recursive calls to main()
1694 or any means that would possibly allow that (e.g. taking address of main()).
1695 The correct solution is not using main() as entry point for kdeinit modules,
1696 but only kdemain().
1698 extern "C" void _main(void);
1699 extern "C" void __call_ctors__Fv(void);
1700 static int main_called = 0;
1701 void _main(void)
1703 if (main_called)
1704 return;
1705 main_called = 1;
1706 __call_ctors__Fv ();
1708 #endif
1710 static void secondary_child_handler(int)
1712 waitpid(-1, 0, WNOHANG);
1715 int main(int argc, char **argv, char **envp)
1717 int i;
1718 pid_t pid;
1719 bool do_fork = true;
1720 int launch_klauncher = 1;
1721 int launch_kded = 1;
1722 int keep_running = 1;
1723 d.suicide = false;
1725 /** Save arguments first... **/
1726 char **safe_argv = (char **) malloc( sizeof(char *) * argc);
1727 for(i = 0; i < argc; i++)
1729 safe_argv[i] = strcpy((char*)malloc(strlen(argv[i])+1), argv[i]);
1730 if (strcmp(safe_argv[i], "--no-klauncher") == 0)
1731 launch_klauncher = 0;
1732 if (strcmp(safe_argv[i], "--no-kded") == 0)
1733 launch_kded = 0;
1734 #ifdef Q_WS_MACX
1735 // make it nofork to match KUniqueApplication, technically command-line incompatible
1736 if (strcmp(safe_argv[i], "--nofork") == 0)
1737 #else
1738 if (strcmp(safe_argv[i], "--no-fork") == 0)
1739 #endif
1740 do_fork = false;
1741 if (strcmp(safe_argv[i], "--suicide") == 0)
1742 d.suicide = true;
1743 if (strcmp(safe_argv[i], "--exit") == 0)
1744 keep_running = 0;
1745 if (strcmp(safe_argv[i], "--help") == 0)
1747 printf("Usage: kdeinit4 [options]\n");
1748 // printf(" --no-dcop Do not start dcopserver\n");
1749 #ifdef Q_WS_MACX
1750 printf(" --nofork Do not fork\n");
1751 #else
1752 printf(" --no-fork Do not fork\n");
1753 #endif
1754 // printf(" --no-klauncher Do not start klauncher\n");
1755 printf(" --no-kded Do not start kded\n");
1756 printf(" --suicide Terminate when no KDE applications are left running\n");
1757 // printf(" --exit Terminate when kded has run\n");
1758 exit(0);
1762 cleanup_fds();
1764 if (do_fork) {
1765 #ifdef Q_WS_MACX
1766 mac_fork_and_reexec_self();
1767 #else
1768 pipe(d.initpipe);
1770 // Fork here and let parent process exit.
1771 // Parent process may only exit after all required services have been
1772 // launched. (dcopserver/klauncher and services which start with '+')
1773 KDE_signal( SIGCHLD, secondary_child_handler);
1774 if (fork() > 0) // Go into background
1776 close(d.initpipe[1]);
1777 d.initpipe[1] = -1;
1778 // wait till init is complete
1779 char c;
1780 while( read(d.initpipe[0], &c, 1) < 0)
1782 // then exit;
1783 close(d.initpipe[0]);
1784 d.initpipe[0] = -1;
1785 return 0;
1787 close(d.initpipe[0]);
1788 d.initpipe[0] = -1;
1789 #endif
1792 /** We start a few processes (including klauncher and kded) before
1793 * we close our pipe, so make sure it doesn't leak */
1794 if (d.initpipe[1] != -1)
1795 fcntl(d.initpipe[1], F_SETFD, FD_CLOEXEC);
1797 d.my_pid = getpid();
1799 /** Make process group leader (for shutting down children later) **/
1800 if(keep_running)
1801 setsid();
1803 /** Create our instance **/
1804 s_instance = new KComponentData("kdeinit4", QByteArray(), KComponentData::SkipMainComponentRegistration);
1806 /** Prepare to change process name **/
1807 proctitle_init(argc, argv, envp);
1808 kdeinit_library_path();
1809 // Don't make our instance the global instance
1810 // (do it only after kdeinit_library_path, that one indirectly uses KConfig,
1811 // which seems to be buggy and always use KGlobal instead of the matching KComponentData)
1812 Q_ASSERT(!KGlobal::hasMainComponent());
1813 // don't change envvars before proctitle_init()
1814 unsetenv("LD_BIND_NOW");
1815 unsetenv("DYLD_BIND_AT_LAUNCH");
1816 KApplication::loadedByKdeinit = true;
1818 d.maxname = strlen(argv[0]);
1819 d.launcher_pid = 0;
1820 d.kded_pid = 0;
1821 d.wrapper = -1;
1822 d.wrapper_old = -1;
1823 d.accepted_fd = -1;
1824 d.debug_wait = false;
1825 d.launcher_ok = false;
1826 children = NULL;
1827 init_signals();
1828 #ifdef Q_WS_X11
1829 setupX();
1830 #endif
1832 if (keep_running)
1835 * Create ~/.kde/tmp-<hostname>/kdeinit4-<display> socket for incoming wrapper
1836 * requests.
1838 init_kdeinit_socket();
1840 #ifdef Q_WS_X11
1841 if (!d.suicide && qgetenv("KDE_IS_PRELINKED").isEmpty())
1843 QString konq = KStandardDirs::locate("lib", "libkonq.so.5", *s_instance);
1844 // can't use KLibLoader here as it would unload the library
1845 // again
1846 if (!konq.isEmpty()) {
1847 QLibrary l(konq);
1848 l.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1849 l.load();
1852 #endif
1853 if (launch_klauncher)
1855 pid = launch( 1, "klauncher", 0 );
1856 #ifndef NDEBUG
1857 fprintf(stderr, "kdeinit4: Launched KLauncher, pid = %ld result = %d\n", (long) pid, d.result);
1858 #endif
1859 handle_requests(pid); // Wait for klauncher to be ready
1862 #ifdef Q_WS_X11
1863 X11fd = initXconnection();
1864 #endif
1867 QFont::initialize();
1868 setlocale (LC_ALL, "");
1869 setlocale (LC_NUMERIC, "C");
1870 #ifdef Q_WS_X11
1871 if (XSupportsLocale ())
1873 // Similar to QApplication::create_xim()
1874 // but we need to use our own display
1875 XOpenIM (X11display, 0, 0, 0);
1877 #endif
1880 if (launch_kded)
1882 pid = launch( 1, KDED_EXENAME, 0 );
1883 #ifndef NDEBUG
1884 fprintf(stderr, "kdeinit4: Launched KDED, pid = %ld result = %d\n", (long) pid, d.result);
1885 #endif
1886 d.kded_pid = pid;
1887 handle_requests(pid);
1890 for(i = 1; i < argc; i++)
1892 if (safe_argv[i][0] == '+')
1894 pid = launch( 1, safe_argv[i]+1, 0);
1895 #ifndef NDEBUG
1896 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i]+1, (long) pid, d.result);
1897 #endif
1898 handle_requests(pid);
1900 else if (safe_argv[i][0] == '-')
1902 // Ignore
1904 else
1906 pid = launch( 1, safe_argv[i], 0 );
1907 #ifndef NDEBUG
1908 fprintf(stderr, "kdeinit4: Launched '%s', pid = %ld result = %d\n", safe_argv[i], (long) pid, d.result);
1909 #endif
1913 /** Free arguments **/
1914 for(i = 0; i < argc; i++)
1916 free(safe_argv[i]);
1918 free (safe_argv);
1920 proctitle_set("kdeinit4 Running...");
1922 if (!keep_running)
1923 return 0;
1925 if (d.initpipe[1] != -1)
1927 char c = 0;
1928 write(d.initpipe[1], &c, 1); // Kdeinit is started.
1929 close(d.initpipe[1]);
1930 d.initpipe[1] = -1;
1933 handle_requests(0);
1935 return 0;