not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / backend / process.c
blob745f3cf4eb4ae29e79cee63f541a1c4aa7852e55
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2001-2004 Oswald Buddenhagen <ossi@kde.org>
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of a copyright holder shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from the copyright holder.
31 * xdm - display manager daemon
32 * Author: Keith Packard, MIT X Consortium
34 * subdaemon and external process management and communication
37 #include "dm.h"
38 #include "dm_error.h"
39 #if defined(SINGLE_PIPE) && !defined(__FreeBSD__)
40 # include "dm_socket.h"
41 #endif
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <stdarg.h>
46 #include <signal.h>
47 #include <unistd.h>
48 #ifdef _POSIX_PRIORITY_SCHEDULING
49 # include <sched.h>
50 #endif
53 SIGFUNC Signal( int sig, SIGFUNC handler )
55 #ifndef __EMX__
56 struct sigaction sigact, osigact;
57 sigact.sa_handler = handler;
58 sigemptyset( &sigact.sa_mask );
59 # ifdef SA_RESTART
60 sigact.sa_flags = SA_RESTART;
61 # else
62 sigact.sa_flags = 0;
63 # endif
64 sigaction( sig, &sigact, &osigact );
65 return osigact.sa_handler;
66 #else
67 return signal( sig, handler );
68 #endif
72 void
73 terminateProcess( int pid, int sig )
75 kill( pid, sig );
76 #ifdef SIGCONT
77 kill( pid, SIGCONT );
78 #endif
82 static fd_set closeMask;
83 static int max = -1;
85 void
86 registerCloseOnFork( int fd )
88 FD_SET( fd, &closeMask );
89 if (fd > max)
90 max = fd;
93 void
94 clearCloseOnFork( int fd )
96 FD_CLR( fd, &closeMask );
99 void
100 closeNclearCloseOnFork( int fd )
102 close( fd );
103 FD_CLR( fd, &closeMask );
106 static void
107 closeOnFork( void )
109 int fd;
111 for (fd = 0; fd <= max; fd++)
112 if (FD_ISSET( fd, &closeMask ))
113 close( fd );
114 FD_ZERO( &closeMask );
115 max = -1;
119 Fork( volatile int *pidr )
121 int pid;
123 sigset_t ss, oss;
124 sigfillset( &ss );
125 sigprocmask( SIG_SETMASK, &ss, &oss );
127 if (!(pid = fork())) {
128 #ifdef SIGCHLD
129 (void)Signal( SIGCHLD, SIG_DFL );
130 #endif
131 (void)Signal( SIGTERM, SIG_DFL );
132 (void)Signal( SIGINT, SIG_IGN ); /* for -nodaemon */
133 (void)Signal( SIGPIPE, SIG_DFL );
134 (void)Signal( SIGALRM, SIG_DFL );
135 (void)Signal( SIGHUP, SIG_DFL );
136 sigemptyset( &ss );
137 sigprocmask( SIG_SETMASK, &ss, NULL );
138 closeOnFork();
139 return 0;
141 *pidr = pid;
143 sigprocmask( SIG_SETMASK, &oss, 0 );
145 return pid;
148 static void
149 cldCatcher( int n ATTR_UNUSED )
154 Wait4( volatile int *pid )
156 int result;
157 sigset_t ss, oss;
158 struct sigaction osa;
160 sigfillset( &ss );
161 sigprocmask( SIG_SETMASK, &ss, &oss );
162 sigaction( SIGCHLD, 0, &osa );
163 if (osa.sa_handler == SIG_DFL)
164 Signal( SIGCHLD, cldCatcher );
165 for (;;) {
166 switch (waitpid( *pid, &result, WNOHANG )) {
167 case 0:
168 sigsuspend( &oss );
169 break;
170 case -1:
171 debug( "Wait4(%d) failed: %m\n", *pid );
172 result = 0;
173 /* fallthrough */
174 default:
175 *pid = 0;
176 if (osa.sa_handler == SIG_DFL)
177 Signal( SIGCHLD, SIG_DFL );
178 sigprocmask( SIG_SETMASK, &oss, 0 );
179 return wcFromWait( result );
185 void
186 execute( char **argv, char **env )
188 debug( "execute: %[s ; %[s\n", argv, env );
189 execve( argv[0], argv, env );
191 * In case this is a shell script which hasn't been
192 * made executable (or this is a SYSV box), do
193 * a reasonable thing
195 if (errno != ENOENT) {
196 char **newargv;
197 FILE *f;
198 int nu;
199 char program[1024];
202 * emulate BSD kernel behaviour -- read
203 * the first line; check if it starts
204 * with "#!", in which case it uses
205 * the rest of the line as the name of
206 * program to run. Else use "/bin/sh".
208 if (!(f = fopen( argv[0], "r" )))
209 return;
210 if (!fGets( program, sizeof(program), f )) {
211 fclose( f );
212 return;
214 fclose( f );
215 if (!strncmp( program, "#!", 2 ))
216 newargv = parseArgs( 0, program + 2 );
217 else
218 newargv = addStrArr( 0, "/bin/sh", 7 );
219 if (!newargv)
220 return;
221 nu = arrLen( newargv );
222 if (!(argv = xCopyStrArr( nu, argv )))
223 return;
224 memcpy( argv, newargv, sizeof(char *) * nu );
225 debug( "shell script execution: %[s\n", argv );
226 execve( argv[0], argv, env );
231 runAndWait( char **args, char **env )
233 int pid, ret;
235 switch (Fork( &pid )) {
236 case 0:
237 execute( args, env );
238 logError( "Cannot execute %\"s: %m\n", args[0] );
239 exit( 127 );
240 case -1:
241 logError( "Cannot fork to execute %\"s: %m\n", args[0] );
242 return wcCompose( 0, 0, 127 );
244 ret = Wait4( &pid );
245 return wcFromWait( ret );
248 FILE *
249 pOpen( char **what, char m, volatile int *pid )
251 int dp[2];
253 if (pipe( dp ))
254 return 0;
255 switch (Fork( pid )) {
256 case 0:
257 if (m == 'r')
258 dup2( dp[1], 1 );
259 else
260 dup2( dp[0], 0 );
261 close( dp[0] );
262 close( dp[1] );
263 execute( what, environ );
264 logError( "Cannot execute %\"s: %m\n", what[0] );
265 exit( 127 );
266 case -1:
267 close( dp[0] );
268 close( dp[1] );
269 logError( "Cannot fork to execute %\"s: %m\n", what[0] );
270 return 0;
272 if (m == 'r') {
273 close( dp[1] );
274 return fdopen( dp[0], "r" );
275 } else {
276 close( dp[0] );
277 return fdopen( dp[1], "w" );
282 pClose( FILE *f, volatile int *pid )
284 fclose( f );
285 return Wait4( pid );
288 char *
289 locate( const char *exe )
291 int len;
292 char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
294 if (!(path = getenv( "PATH" ))) {
295 logError( "Cannot execute %'s: $PATH not set.\n", exe );
296 return 0;
298 len = strlen( exe );
299 name = nambuf + PATH_MAX - len;
300 memcpy( name, exe, len + 1 );
301 *--name = '/';
302 do {
303 if (!(pathe = strchr( path, ':' )))
304 pathe = path + strlen( path );
305 len = pathe - path;
306 if (len && !(len == 1 && *path == '.')) {
307 thenam = name - len;
308 if (thenam >= nambuf) {
309 memcpy( thenam, path, len );
310 if (!access( thenam, X_OK )) {
311 strDup( &name, thenam );
312 return name;
316 path = pathe;
317 } while (*path++ != '\0');
318 logError( "Cannot execute %'s: not in $PATH.\n", exe );
319 return 0;
323 static GTalk *curtalk;
325 void
326 gSet( GTalk *tlk )
328 curtalk = tlk;
331 void
332 gCloseOnExec( GPipe *pajp )
334 fcntl( pajp->fd.r, F_SETFD, FD_CLOEXEC );
335 #ifndef SINGLE_PIPE
336 fcntl( pajp->fd.w, F_SETFD, FD_CLOEXEC );
337 #endif
340 #if !defined(SINGLE_PIPE) || defined(__FreeBSD__)
341 # define make_pipe(h) pipe( h )
342 #else
343 # define make_pipe(h) socketpair( AF_UNIX, SOCK_STREAM, 0, h )
344 #endif
347 gFork( GPipe *pajp, const char *pname, char *cname,
348 GPipe *ogp, char *cgname,
349 GPipe *gp,
350 volatile int *pidr )
352 int opipe[2], ogpipe[2];
353 #ifndef SINGLE_PIPE
354 int ipipe[2], igpipe[2];
355 #endif
356 int pid;
358 if (make_pipe( opipe ))
359 goto badp1;
360 #ifndef SINGLE_PIPE
361 if (pipe( ipipe ))
362 goto badp2;
363 #endif
364 if (ogp) {
365 if (make_pipe( ogpipe ))
366 #ifdef SINGLE_PIPE
368 #else
369 goto badp3;
370 if (pipe( igpipe ))
372 close( ogpipe[0] );
373 close( ogpipe[1] );
374 badp3:
375 close( ipipe[0] );
376 close( ipipe[1] );
377 badp2:
378 #endif
379 close( opipe[0] );
380 close( opipe[1] );
381 badp1:
382 logError( "Cannot start %s, pipe() failed", cname );
383 if (cname)
384 free( cname );
385 return -1;
388 registerCloseOnFork( opipe[1] );
389 #ifndef SINGLE_PIPE
390 registerCloseOnFork( ipipe[0] );
391 #endif
392 if (ogp) {
393 registerCloseOnFork( ogpipe[1] );
394 #ifndef SINGLE_PIPE
395 registerCloseOnFork( igpipe[0] );
396 #endif
398 if (gp) {
399 clearCloseOnFork( gp->fd.r );
400 #ifndef SINGLE_PIPE
401 clearCloseOnFork( gp->fd.w );
402 #endif
404 if ((pid = Fork( pidr ))) {
405 if (gp) {
406 registerCloseOnFork( gp->fd.r );
407 #ifndef SINGLE_PIPE
408 registerCloseOnFork( gp->fd.w );
409 #endif
411 if (ogp) {
412 close( ogpipe[0] );
413 #ifndef SINGLE_PIPE
414 close( igpipe[1] );
415 #endif
417 close( opipe[0] );
418 #ifndef SINGLE_PIPE
419 close( ipipe[1] );
420 #endif
422 switch (pid) {
423 case -1:
424 closeNclearCloseOnFork( opipe[1] );
425 #ifndef SINGLE_PIPE
426 closeNclearCloseOnFork( ipipe[0] );
427 #endif
428 if (ogp) {
429 closeNclearCloseOnFork( ogpipe[1] );
430 #ifndef SINGLE_PIPE
431 closeNclearCloseOnFork( igpipe[0] );
432 #endif
434 logError( "Cannot start %s, fork() failed\n", cname );
435 if (cname)
436 free( cname );
437 return -1;
438 case 0:
439 #ifndef SINGLE_PIPE
440 pajp->fd.w = ipipe[1];
441 registerCloseOnFork( ipipe[1] );
442 #endif
443 pajp->fd.r = opipe[0];
444 registerCloseOnFork( opipe[0] );
445 pajp->who = (char *)pname;
446 if (ogp) {
447 #ifndef SINGLE_PIPE
448 ogp->fd.w = igpipe[1];
449 registerCloseOnFork( igpipe[1] );
450 #endif
451 ogp->fd.r = ogpipe[0];
452 registerCloseOnFork( ogpipe[0] );
453 ogp->who = (char *)pname;
455 if (cname)
456 free( cname );
457 return 0;
458 default:
459 pajp->fd.w = opipe[1];
460 #ifndef SINGLE_PIPE
461 pajp->fd.r = ipipe[0];
462 #endif
463 pajp->who = cname;
464 if (ogp) {
465 ogp->fd.w = ogpipe[1];
466 #ifndef SINGLE_PIPE
467 ogp->fd.r = igpipe[0];
468 #endif
469 ogp->who = cgname;
471 return pid;
476 gOpen( GProc *proc, char **argv, const char *what, char **env, char *cname,
477 GPipe *gp )
479 char **margv;
480 int pip[2];
481 char coninfo[32];
483 if (proc->pid > 0) {
484 logError( "%s already running\n", cname );
485 if (cname)
486 free( cname );
487 return -1;
489 if (!(margv = xCopyStrArr( 1, argv ))) {
490 if (cname)
491 free( cname );
492 return -1;
494 #if KDM_LIBEXEC_STRIP == -1
495 if (!strApp( margv, KDM_LIBEXEC_SUFFIX, progname, what, (char *)0 ))
496 #elif KDM_LIBEXEC_STRIP == 0
497 if (!strApp( margv, progpath, what, (char *)0 ))
498 #else
499 if (!strApp( margv, progpath, "/" KDM_LIBEXEC_SUFFIX, progname, what, (char *)0 ))
500 #endif
502 free( margv );
503 if (cname)
504 free( cname );
505 return -1;
507 if (pipe( pip )) {
508 logError( "Cannot start %s, pipe() failed\n", cname );
509 if (cname)
510 free( cname );
511 goto fail;
513 switch (gFork( &proc->pipe, 0, cname, 0, 0, gp, &proc->pid )) {
514 case -1:
515 close( pip[1] );
516 fail1:
517 close( pip[0] );
518 fail:
519 free( margv[0] );
520 free( margv );
521 return -1;
522 case 0:
523 (void)Signal( SIGPIPE, SIG_IGN );
524 close( pip[0] );
525 fcntl( pip[1], F_SETFD, FD_CLOEXEC );
526 if (gp)
527 sprintf( coninfo, "CONINFO=%d %d %d %d",
528 proc->pipe.fd.r, proc->pipe.fd.w, gp->fd.r, gp->fd.w );
529 else
530 sprintf( coninfo, "CONINFO=%d %d",
531 proc->pipe.fd.r, proc->pipe.fd.w );
532 env = putEnv( coninfo, env );
533 if (debugLevel & DEBUG_VALGRIND) {
534 char **nmargv = xCopyStrArr( 1, margv );
535 nmargv[0] = locate( "valgrind" );
536 execute( nmargv, env );
537 } else if (debugLevel & DEBUG_STRACE) {
538 char **nmargv = xCopyStrArr( 1, margv );
539 nmargv[0] = locate( "strace" );
540 execute( nmargv, env );
541 } else
542 execute( margv, env );
543 write( pip[1], "", 1 );
544 exit( 1 );
545 default:
546 (void)Signal( SIGPIPE, SIG_IGN );
547 close( pip[1] );
548 if (reader( pip[0], coninfo, 1 )) {
549 Wait4( &proc->pid );
550 logError( "Cannot execute %\"s (%s)\n", margv[0], cname );
551 gClosen( &proc->pipe );
552 goto fail1;
554 close( pip[0] );
555 debug( "started %s (%\"s), pid %d\n", cname, margv[0], proc->pid );
556 free( margv[0] );
557 free( margv );
558 gSendInt( debugLevel );
559 return 0;
563 static void
564 _gClosen( GPipe *pajp )
566 closeNclearCloseOnFork( pajp->fd.r );
567 #ifndef SINGLE_PIPE
568 closeNclearCloseOnFork( pajp->fd.w );
569 pajp->fd.w =
570 #endif
571 pajp->fd.r = -1;
574 void
575 gClosen( GPipe *pajp )
577 _gClosen( pajp );
578 if (pajp->who)
579 free( pajp->who );
580 pajp->who = 0;
584 gClose( GProc *proc, GPipe *gp, int force )
586 int ret;
588 if (proc->pid <= 0) {
589 debug( "whoops, gClose while helper not running\n" );
590 return 0;
592 _gClosen( &proc->pipe );
593 if (gp)
594 gClosen( gp );
595 if (force)
596 terminateProcess( proc->pid, SIGTERM );
597 ret = Wait4( &proc->pid );
598 if (wcSig( ret ) ? wcSig( ret ) != SIGTERM :
599 (wcCode( ret ) < EX_NORMAL || wcCode( ret ) > EX_MAX))
600 logError( "Abnormal termination of %s, code %d, signal %d\n",
601 proc->pipe.who, wcCode( ret ), wcSig( ret ) );
602 debug( "closed %s\n", proc->pipe.who );
603 if (proc->pipe.who)
604 free( proc->pipe.who );
605 proc->pipe.who = 0;
606 return ret;
609 static void ATTR_NORETURN
610 gErr( void )
612 Longjmp( curtalk->errjmp, 1 );
615 static void
616 gRead( void *buf, int len )
618 if (reader( curtalk->pipe->fd.r, buf, len ) != len) {
619 logError( "Cannot read from %s\n", curtalk->pipe->who );
620 gErr();
624 static void
625 gWrite( const void *buf, int len )
627 if (writer( curtalk->pipe->fd.w, buf, len ) != len) {
628 logError( "Cannot write to %s\n", curtalk->pipe->who );
629 gErr();
631 #ifdef _POSIX_PRIORITY_SCHEDULING
632 if ((debugLevel & DEBUG_HLPCON))
633 sched_yield();
634 #endif
637 void
638 gSendInt( int val )
640 gDebug( "sending int %d (%#x) to %s\n", val, val, curtalk->pipe->who );
641 gWrite( &val, sizeof(val) );
645 gRecvInt()
647 int val;
649 gDebug( "receiving int from %s ...\n", curtalk->pipe->who );
650 gRead( &val, sizeof(val) );
651 gDebug( " -> %d (%#x)\n", val, val );
652 return val;
656 gRecvCmd( int *cmd )
658 gDebug( "receiving command from %s ...\n", curtalk->pipe->who );
659 if (reader( curtalk->pipe->fd.r, cmd, sizeof(*cmd) ) == sizeof(*cmd)) {
660 gDebug( " -> %d\n", *cmd );
661 return 1;
663 gDebug( " -> no data\n" );
664 return False;
667 void
668 gSendArr( int len, const char *data )
670 gDebug( "sending array[%d] %02[*{hhx to %s\n",
671 len, len, data, curtalk->pipe->who );
672 gWrite( &len, sizeof(len) );
673 gWrite( data, len );
676 static char *
677 _gRecvArr( int *rlen )
679 unsigned len;
680 char *buf;
682 gRead( &len, sizeof(len) );
683 *rlen = len;
684 gDebug( " -> %d bytes\n", len );
685 if (!len || len > 0x10000)
686 return (char *)0;
687 if (!(buf = Malloc( len )))
688 gErr();
689 gRead( buf, len );
690 return buf;
693 char *
694 gRecvArr( int *rlen )
696 char *buf;
698 gDebug( "receiving array from %s ...\n", curtalk->pipe->who );
699 buf = _gRecvArr( rlen );
700 gDebug( " -> %02[*{hhx\n", *rlen, buf );
701 return buf;
704 static int
705 _gRecvArrBuf( char *buf )
707 unsigned len;
709 gRead( &len, sizeof(len) );
710 gDebug( " -> %d bytes\n", len );
711 if (len && len < 0x10000)
712 gRead( buf, len );
713 return len;
717 gRecvArrBuf( char *buf )
719 int len;
721 gDebug( "receiving already allocated array from %s ...\n",
722 curtalk->pipe->who );
723 len = _gRecvArrBuf( buf );
724 gDebug( " -> %02[*{hhx\n", len, buf );
725 return len;
729 gRecvStrBuf( char *buf )
731 int len;
733 gDebug( "receiving already allocated string from %s ...\n",
734 curtalk->pipe->who );
735 len = _gRecvArrBuf( buf );
736 gDebug( " -> %\".*s\n", len, buf );
737 return len;
740 void
741 gSendStr( const char *buf )
743 int len;
745 gDebug( "sending string %\"s to %s\n", buf, curtalk->pipe->who );
746 if (buf) {
747 len = strlen( buf ) + 1;
748 gWrite( &len, sizeof(len) );
749 gWrite( buf, len );
750 } else
751 gWrite( &buf, sizeof(int) );
754 void
755 gSendNStr( const char *buf, int len )
757 int tlen = len + 1;
758 gDebug( "sending string %\".*s to %s\n", len, buf, curtalk->pipe->who );
759 gWrite( &tlen, sizeof(tlen) );
760 gWrite( buf, len );
761 gWrite( "", 1 );
764 void
765 gSendStrN( const char *buf, int len )
767 if (buf)
768 gSendNStr( buf, strnlen( buf, len ) );
769 else
770 gSendStr( buf );
773 char *
774 gRecvStr()
776 int len;
777 char *buf;
779 gDebug( "receiving string from %s ...\n", curtalk->pipe->who );
780 buf = _gRecvArr( &len );
781 gDebug( " -> %\".*s\n", len, buf );
782 return buf;
785 static void
786 _gSendStrArr( int num, char **data )
788 char **cdata;
790 gWrite( &num, sizeof(num) );
791 for (cdata = data; --num >= 0; cdata++)
792 gSendStr( *cdata );
796 void
797 gSendStrArr (int num, char **data)
799 gDebug( "sending string array[%d] to %s\n", num, curtalk->pipe->who );
800 _gSendStrArr( num, data );
804 char **
805 gRecvStrArr( int *rnum )
807 int num;
808 char **argv, **cargv;
810 gDebug( "receiving string array from %s ...\n", curtalk->pipe->who );
811 gRead( &num, sizeof(num) );
812 gDebug( " -> %d strings\n", num );
813 *rnum = num;
814 if (!num)
815 return (char **)0;
816 if (!(argv = Malloc( num * sizeof(char *) )))
817 gErr();
818 for (cargv = argv; --num >= 0; cargv++)
819 *cargv = gRecvStr();
820 return argv;
823 void
824 gSendArgv( char **argv )
826 int num;
828 if (argv) {
829 for (num = 0; argv[num]; num++);
830 gDebug( "sending argv[%d] to %s ...\n", num, curtalk->pipe->who );
831 _gSendStrArr( num + 1, argv );
832 } else {
833 gDebug( "sending NULL argv to %s\n", curtalk->pipe->who );
834 gWrite( &argv, sizeof(int) );
838 char **
839 gRecvArgv()
841 int num;
843 return gRecvStrArr( &num );