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.
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>
41 extern char **environ
;
43 static char *getDisplay()
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)
58 #if defined(NO_DISPLAY)
59 display
= "NODISPLAY";
61 display
= getenv("DISPLAY");
63 display
= getenv("QWS_DISPLAY");
65 if (!display
|| !*display
)
69 result
= (char*)malloc(strlen(display
)+1);
73 strcpy(result
, display
);
74 screen
= strrchr(result
, '.');
75 colon
= strrchr(result
, ':');
76 if (screen
&& (screen
> colon
))
78 while((i
= strchr(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
)
91 while ( bytes_left
> 0)
93 result
= write(sock
, buffer
, bytes_left
);
101 else if ((result
== -1) && (errno
!= EINTR
) && (errno
!= EAGAIN
))
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
)
114 int bytes_left
= len
;
115 while ( bytes_left
> 0)
117 result
= read(sock
, buffer
, bytes_left
);
121 bytes_left
-= result
;
123 else if (result
== 0)
125 else if ((result
== -1) && (errno
!= EINTR
) && (errno
!= EAGAIN
))
131 static int openSocket()
133 kde_socklen_t socklen
;
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");
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");
156 if (strlen(home_dir
) > (MAX_SOCK_FILE
-100))
158 fprintf(stderr
, "Warning: Home directory path too long!\n");
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: ");
176 sock_file
[sizeof(sock_file
)-1] = '\0';
178 /* append $DISPLAY */
179 display
= getDisplay();
180 #if !defined (NO_DISPLAY)
183 fprintf(stderr
, "Error: Could not determine display.\n");
188 if (strlen(sock_file
)+strlen(display
)+strlen("/kdeinit4_")+2 > MAX_SOCK_FILE
)
190 fprintf(stderr
, "Warning: Socket name will be too long.\n");
194 strcat(sock_file
, "/kdeinit4_");
195 #if !defined (NO_DISPLAY)
196 strcat(sock_file
, display
);
200 if (strlen(sock_file
) >= sizeof(server
.sun_path
))
202 fprintf(stderr
, "Warning: Path of socketfile exceeds UNIX_PATH_MAX.\n");
207 * create the socket stream
209 s
= socket(PF_UNIX
, SOCK_STREAM
, 0);
212 perror("Warning: socket() failed: ");
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
);
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
)
238 sa
.sa_handler
= SIG_DFL
;
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 */
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 ??? */
292 static int kwrapper_run( pid_t wrapped
, int sock
)
294 klauncher_header header
;
298 kwrapper_pid
= wrapped
;
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
);
309 buffer
= (char *) malloc(header
.arg_length
);
312 fprintf(stderr
, "Error: malloc() failed\n");
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
);
324 status
= ((long *) buffer
)[1];
328 int main(int argc
, char **argv
)
336 klauncher_header header
;
337 char *start
, *p
, *buffer
;
339 const char *tty
= NULL
;
340 long avoid_loops
= 0;
341 const char* startup_id
= NULL
;
347 p
= start
+ strlen(argv
[0]);
350 if (*p
== '/') break;
356 if (strcmp(start
, "kdeinit4_wrapper") == 0)
358 else if (strcmp(start
, "kshell4") == 0)
360 else if (strcmp(start
, "kwrapper4") == 0)
362 else if (strcmp(start
, "kdeinit4_shutdown") == 0)
366 fprintf(stderr
, "Usage: %s\n\n", start
);
367 fprintf(stderr
, "Shuts down kdeinit4 master process and terminates all processes spawned from it.\n");
373 fprintf( stderr
, "Error: Can not contact kdeinit4!\n" );
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 */
383 if (wrapper
|| ext_wrapper
|| kwrapper
)
389 fprintf(stderr
, "Usage: %s <application> [<args>]\n", start
);
390 exit(255); /* usage should be documented somewhere ... */
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 ] );
403 if( !wrapper
&& !ext_wrapper
&& !kwrapper
)
404 { /* was called as a symlink */
406 #if defined(WE_ARE_KWRAPPER)
408 #elif defined(WE_ARE_KSHELL)
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;
427 size
+= sizeof(long); /* empty envs */
429 if (ext_wrapper
|| kwrapper
)
431 if (!getcwd(cwd
, 8192))
433 size
+= strlen(cwd
)+1;
436 size
+= sizeof(long); /* Number of env.vars. */
438 for(; environ
[env_count
] ; env_count
++)
440 int l
= strlen(environ
[env_count
])+1;
447 if (!tty
|| !isatty(2))
449 size
+= strlen(tty
)+1;
453 size
+= sizeof( avoid_loops
);
457 startup_id
= getenv( "DESKTOP_STARTUP_ID" );
458 if( startup_id
== NULL
)
460 size
+= strlen( startup_id
) + 1;
464 header
.cmd
= LAUNCHER_EXEC_NEW
;
466 header
.cmd
= LAUNCHER_KWRAPPER
;
468 header
.cmd
= LAUNCHER_SHELL
;
469 header
.arg_length
= size
;
470 write_socket(sock
, (char *) &header
, sizeof(header
));
472 buffer
= (char *) malloc(size
);
475 fprintf(stderr
, "Error: malloc() failed.");
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;
495 memcpy(p
, &dummy
, sizeof(dummy
)); /* empty envc */
498 if (ext_wrapper
|| kwrapper
)
500 memcpy(p
, cwd
, 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
);
515 memcpy(p
, tty
, strlen(tty
)+1);
520 memcpy( p
, &avoid_loops
, sizeof( avoid_loops
));
521 p
+= sizeof( avoid_loops
);
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");
536 write_socket(sock
, buffer
, size
);
539 if (read_socket(sock
, (char *) &header
, sizeof(header
))==-1)
541 fprintf(stderr
, "Communication error with KInit.\n");
545 if (header
.cmd
== LAUNCHER_OK
)
548 buffer
= (char *) malloc(header
.arg_length
);
551 fprintf(stderr
, "Error: malloc() failed\n");
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
);
559 exit( kwrapper_run( pid
, sock
) );
561 else if (header
.cmd
== LAUNCHER_ERROR
)
563 fprintf(stderr
, "KInit could not launch '%s'.\n", start
);
568 fprintf(stderr
, "Unexpected response from KInit (response = %ld).\n", header
.cmd
);