give CSS stylesheets a higher priority in the Loader.
[kdelibs.git] / kinit / wrapper.c
blobb5df90a20d3e1f983c6f92dd0fd3b35383e164c4
1 /*
2 This file is part of the KDE libraries
3 Copyright (c) 1999 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>
23 #include <config-kstandarddirs.h>
25 #include "klauncher_cmds.h"
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/un.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <pwd.h>
39 #include <signal.h>
41 extern char **environ;
43 static char *getDisplay()
45 const char *display;
46 char *result;
47 char *screen;
48 char *colon;
49 char *i;
52 don't test for a value from qglobal.h but instead distinguish
53 Qt/X11 from Qt/Embedded by the fact that Qt/E apps have -DQWS
54 on the commandline (which in qglobal.h however triggers Q_WS_QWS,
55 but we don't want to include that here) (Simon)
56 #ifdef Q_WS_X11
58 #if defined(NO_DISPLAY)
59 display = "NODISPLAY";
60 #elif !defined(QWS)
61 display = getenv("DISPLAY");
62 #else
63 display = getenv("QWS_DISPLAY");
64 #endif
65 if (!display || !*display)
67 display = ":0";
69 result = (char*)malloc(strlen(display)+1);
70 if (result == NULL)
71 return NULL;
73 strcpy(result, display);
74 screen = strrchr(result, '.');
75 colon = strrchr(result, ':');
76 if (screen && (screen > colon))
77 *screen = '\0';
78 while((i = strchr(result, ':')))
79 *i = '_';
80 return result;
84 * Write 'len' bytes from 'buffer' into 'sock'.
85 * returns 0 on success, -1 on failure.
87 static int write_socket(int sock, char *buffer, int len)
89 ssize_t result;
90 int bytes_left = len;
91 while ( bytes_left > 0)
93 result = write(sock, buffer, bytes_left);
94 if (result > 0)
96 buffer += result;
97 bytes_left -= result;
99 else if (result == 0)
100 return -1;
101 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
102 return -1;
104 return 0;
108 * Read 'len' bytes from 'sock' into 'buffer'.
109 * returns 0 on success, -1 on failure.
111 static int read_socket(int sock, char *buffer, int len)
113 ssize_t result;
114 int bytes_left = len;
115 while ( bytes_left > 0)
117 result = read(sock, buffer, bytes_left);
118 if (result > 0)
120 buffer += result;
121 bytes_left -= result;
123 else if (result == 0)
124 return -1;
125 else if ((result == -1) && (errno != EINTR) && (errno != EAGAIN))
126 return -1;
128 return 0;
131 static int openSocket()
133 kde_socklen_t socklen;
134 int s;
135 struct sockaddr_un server;
136 #define MAX_SOCK_FILE 255
137 char sock_file[MAX_SOCK_FILE + 1];
138 const char *home_dir = getenv("HOME");
139 const char *kde_home = getenv("KDEHOME");
140 char *display;
142 sock_file[0] = sock_file[MAX_SOCK_FILE] = 0;
144 if (!kde_home || !kde_home[0])
146 kde_home = "~/" KDE_DEFAULT_HOME "/";
149 if (kde_home[0] == '~')
151 if (!home_dir || !home_dir[0])
153 fprintf(stderr, "Warning: $HOME not set!\n");
154 return -1;
156 if (strlen(home_dir) > (MAX_SOCK_FILE-100))
158 fprintf(stderr, "Warning: Home directory path too long!\n");
159 return -1;
161 kde_home++;
162 strncpy(sock_file, home_dir, MAX_SOCK_FILE);
164 strncat(sock_file, kde_home, MAX_SOCK_FILE - strlen(sock_file));
166 /** Strip trailing '/' **/
167 if ( sock_file[strlen(sock_file)-1] == '/')
168 sock_file[strlen(sock_file)-1] = 0;
170 strncat(sock_file, "/socket-", MAX_SOCK_FILE - strlen(sock_file));
171 if (gethostname(sock_file+strlen(sock_file), MAX_SOCK_FILE - strlen(sock_file) - 1) != 0)
173 perror("Warning: Could not determine hostname: ");
174 return -1;
176 sock_file[sizeof(sock_file)-1] = '\0';
178 /* append $DISPLAY */
179 display = getDisplay();
180 #if !defined (NO_DISPLAY)
181 if (display == NULL)
183 fprintf(stderr, "Error: Could not determine display.\n");
184 return -1;
186 #endif
188 if (strlen(sock_file)+strlen(display)+strlen("/kdeinit4_")+2 > MAX_SOCK_FILE)
190 fprintf(stderr, "Warning: Socket name will be too long.\n");
191 free (display);
192 return -1;
194 strcat(sock_file, "/kdeinit4_");
195 #if !defined (NO_DISPLAY)
196 strcat(sock_file, display);
197 free(display);
198 #endif
200 if (strlen(sock_file) >= sizeof(server.sun_path))
202 fprintf(stderr, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
203 return -1;
207 * create the socket stream
209 s = socket(PF_UNIX, SOCK_STREAM, 0);
210 if (s < 0)
212 perror("Warning: socket() failed: ");
213 return -1;
216 server.sun_family = AF_UNIX;
217 strcpy(server.sun_path, sock_file);
218 socklen = sizeof(server);
219 if(connect(s, (struct sockaddr *)&server, socklen) == -1)
221 fprintf(stderr, "kdeinit4_wrapper: Warning: connect(%s) failed:", sock_file);
222 perror(" ");
223 close(s);
224 return -1;
226 return s;
229 static pid_t kwrapper_pid;
231 static void sig_pass_handler( int signo );
232 static void setup_signals( void );
234 static void setup_signal_handler( int signo, int clean )
236 struct sigaction sa;
237 if( clean )
238 sa.sa_handler = SIG_DFL;
239 else
240 sa.sa_handler = sig_pass_handler;
241 sigemptyset( &sa.sa_mask );
242 sigaddset( &sa.sa_mask, signo );
243 sa.sa_flags = 0; /* don't use SA_RESTART */
244 sigaction( signo, &sa, 0 );
247 static void sig_pass_handler( int signo )
249 int save_errno = errno;
250 if( signo == SIGTSTP )
251 kill( kwrapper_pid, SIGSTOP ); /* pass the signal to the real process */
252 else /* SIGTSTP wouldn't work ... I don't think is much */
253 kill( kwrapper_pid, signo ); /* of a problem */
255 if( signo == SIGCONT )
256 setup_signals(); /* restore signals */
257 else if( signo == SIGCHLD )
258 ; /* nothing, ignore */
259 else /* do the default action ( most of them quit the app ) */
261 setup_signal_handler( signo, 1 );
262 raise( signo ); /* handle the signal again */
265 errno = save_errno;
268 static void setup_signals()
270 setup_signal_handler( SIGHUP, 0 );
271 setup_signal_handler( SIGINT, 0 );
272 setup_signal_handler( SIGQUIT, 0 );
273 setup_signal_handler( SIGILL, 0 ); /* e.g. this one is probably doesn't make sense to pass */
274 setup_signal_handler( SIGABRT, 0 ); /* but anyway ... */
275 setup_signal_handler( SIGFPE, 0 );
276 /* SIGKILL can't be handled :( */
277 setup_signal_handler( SIGSEGV, 0 );
278 setup_signal_handler( SIGPIPE, 0 );
279 setup_signal_handler( SIGALRM, 0 );
280 setup_signal_handler( SIGTERM, 0 );
281 setup_signal_handler( SIGUSR1, 0 );
282 setup_signal_handler( SIGUSR2, 0 );
283 setup_signal_handler( SIGCHLD, 0 ); /* is this a good idea ??? */
284 setup_signal_handler( SIGCONT, 0 ); /* SIGSTOP can't be handled, but SIGTSTP and SIGCONT can */
285 /* SIGSTOP */ /* which should be enough */
286 setup_signal_handler( SIGTSTP, 0 );
287 setup_signal_handler( SIGTTIN, 0 ); /* is this a good idea ??? */
288 setup_signal_handler( SIGTTOU, 0 ); /* is this a good idea ??? */
289 /* some more ? */
292 static int kwrapper_run( pid_t wrapped, int sock )
294 klauncher_header header;
295 char *buffer;
296 long pid, status;
298 kwrapper_pid = wrapped;
299 setup_signals();
301 read_socket(sock, (char *)&header, sizeof(header));
303 if (header.cmd != LAUNCHER_DIED)
305 fprintf(stderr, "Unexpected response from KInit (response = %ld).\n", header.cmd);
306 exit(255);
309 buffer = (char *) malloc(header.arg_length);
310 if (buffer == NULL)
312 fprintf(stderr, "Error: malloc() failed\n");
313 exit(255);
316 read_socket(sock, buffer, header.arg_length);
317 pid = ((long *) buffer)[0];
318 if( pid != kwrapper_pid)
320 fprintf(stderr, "Unexpected LAUNCHER_DIED from KInit - pid = %ld\n", pid);
321 exit(255);
324 status = ((long *) buffer)[1];
325 return (int) status;
328 int main(int argc, char **argv)
330 int i;
331 int wrapper = 0;
332 int ext_wrapper = 0;
333 int kwrapper = 0;
334 long arg_count;
335 long env_count;
336 klauncher_header header;
337 char *start, *p, *buffer;
338 char cwd[8192];
339 const char *tty = NULL;
340 long avoid_loops = 0;
341 const char* startup_id = NULL;
342 int sock;
344 long size = 0;
346 start = argv[0];
347 p = start + strlen(argv[0]);
348 while (--p > start)
350 if (*p == '/') break;
352 if ( p > start)
353 p++;
354 start = p;
356 if (strcmp(start, "kdeinit4_wrapper") == 0)
357 wrapper = 1;
358 else if (strcmp(start, "kshell4") == 0)
359 ext_wrapper = 1;
360 else if (strcmp(start, "kwrapper4") == 0)
361 kwrapper = 1;
362 else if (strcmp(start, "kdeinit4_shutdown") == 0)
364 if( argc > 1)
366 fprintf(stderr, "Usage: %s\n\n", start);
367 fprintf(stderr, "Shuts down kdeinit4 master process and terminates all processes spawned from it.\n");
368 exit( 255 );
370 sock = openSocket();
371 if( sock < 0 )
373 fprintf( stderr, "Error: Can not contact kdeinit4!\n" );
374 exit( 255 );
376 header.cmd = LAUNCHER_TERMINATE_KDE;
377 header.arg_length = 0;
378 write_socket(sock, (char *) &header, sizeof(header));
379 read_socket(sock, (char *) &header, 1); /* wait for the socket to close */
380 return 0;
383 if (wrapper || ext_wrapper || kwrapper)
385 argv++;
386 argc--;
387 if (argc < 1)
389 fprintf(stderr, "Usage: %s <application> [<args>]\n", start);
390 exit(255); /* usage should be documented somewhere ... */
392 start = argv[0];
395 sock = openSocket();
396 if( sock < 0 ) /* couldn't contact kdeinit4, start argv[ 0 ] directly */
398 execvp( argv[ 0 ], argv );
399 fprintf( stderr, "Error: Can not run %s !\n", argv[ 0 ] );
400 exit( 255 );
403 if( !wrapper && !ext_wrapper && !kwrapper )
404 { /* was called as a symlink */
405 avoid_loops = 1;
406 #if defined(WE_ARE_KWRAPPER)
407 kwrapper = 1;
408 #elif defined(WE_ARE_KSHELL)
409 ext_wrapper = 1;
410 #else
411 wrapper = 1;
412 #endif
415 arg_count = argc;
417 size += sizeof(long); /* Number of arguments*/
419 size += strlen(start)+1; /* Size of first argument. */
421 for(i = 1; i < argc; i++)
423 size += strlen(argv[i])+1;
425 if( wrapper )
427 size += sizeof(long); /* empty envs */
429 if (ext_wrapper || kwrapper)
431 if (!getcwd(cwd, 8192))
432 cwd[0] = '\0';
433 size += strlen(cwd)+1;
435 env_count = 0;
436 size += sizeof(long); /* Number of env.vars. */
438 for(; environ[env_count] ; env_count++)
440 int l = strlen(environ[env_count])+1;
441 size += l;
444 if( kwrapper )
446 tty = ttyname(1);
447 if (!tty || !isatty(2))
448 tty = "";
449 size += strlen(tty)+1;
453 size += sizeof( avoid_loops );
455 if( !wrapper )
457 startup_id = getenv( "DESKTOP_STARTUP_ID" );
458 if( startup_id == NULL )
459 startup_id = "";
460 size += strlen( startup_id ) + 1;
463 if (wrapper)
464 header.cmd = LAUNCHER_EXEC_NEW;
465 else if (kwrapper)
466 header.cmd = LAUNCHER_KWRAPPER;
467 else
468 header.cmd = LAUNCHER_SHELL;
469 header.arg_length = size;
470 write_socket(sock, (char *) &header, sizeof(header));
472 buffer = (char *) malloc(size);
473 if (buffer == NULL)
475 fprintf(stderr, "Error: malloc() failed.");
476 exit(255);
478 p = buffer;
480 memcpy(p, &arg_count, sizeof(arg_count));
481 p += sizeof(arg_count);
483 memcpy(p, start, strlen(start)+1);
484 p += strlen(start)+1;
486 for(i = 1; i < argc; i++)
488 memcpy(p, argv[i], strlen(argv[i])+1);
489 p += strlen(argv[i])+1;
492 if( wrapper )
494 long dummy = 0;
495 memcpy(p, &dummy, sizeof(dummy)); /* empty envc */
496 p+= sizeof( dummy );
498 if (ext_wrapper || kwrapper)
500 memcpy(p, cwd, strlen(cwd)+1);
501 p+= strlen(cwd)+1;
503 memcpy(p, &env_count, sizeof(env_count));
504 p+= sizeof(env_count);
506 for(i = 0; i < env_count; i++)
508 int l = strlen(environ[i])+1;
509 memcpy(p, environ[i], l);
510 p += l;
513 if( kwrapper )
515 memcpy(p, tty, strlen(tty)+1);
516 p+=strlen(tty)+1;
520 memcpy( p, &avoid_loops, sizeof( avoid_loops ));
521 p += sizeof( avoid_loops );
523 if( !wrapper )
525 memcpy(p, startup_id, strlen(startup_id)+1);
526 p+= strlen(startup_id)+1;
529 if( p - buffer != size ) /* should fail only if you change this source and do */
530 /* a stupid mistake, it should be assert() actually */
532 fprintf(stderr, "Oops. Invalid format.\n");
533 exit(255);
536 write_socket(sock, buffer, size);
537 free( buffer );
539 if (read_socket(sock, (char *) &header, sizeof(header))==-1)
541 fprintf(stderr, "Communication error with KInit.\n");
542 exit(255);
545 if (header.cmd == LAUNCHER_OK)
547 long pid;
548 buffer = (char *) malloc(header.arg_length);
549 if (buffer == NULL)
551 fprintf(stderr, "Error: malloc() failed\n");
552 exit(255);
554 read_socket(sock, buffer, header.arg_length);
555 pid = *((long *) buffer);
556 if( !kwrapper ) /* kwrapper shouldn't print any output */
557 printf("Launched ok, pid = %ld\n", pid);
558 else
559 exit( kwrapper_run( pid, sock ) );
561 else if (header.cmd == LAUNCHER_ERROR)
563 fprintf(stderr, "KInit could not launch '%s'.\n", start);
564 exit(255);
566 else
568 fprintf(stderr, "Unexpected response from KInit (response = %ld).\n", header.cmd);
569 exit(255);
571 exit(0);