plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

daemonize.c (3190B)


      1 #include <u.h>
      2 #include <sys/time.h>
      3 #include <sys/resource.h>
      4 #include "threadimpl.h"
      5 
      6 #undef waitpid
      7 #undef pipe
      8 #undef wait
      9 
     10 static int sigpid;
     11 static int threadpassfd = -1;
     12 static int gotsigchld;
     13 
     14 static void
     15 child(void)
     16 {
     17 	int status, pid;
     18 	struct rlimit rl;
     19 
     20 	notedisable("sys: child");
     21 	pid = waitpid(sigpid, &status, 0);
     22 	if(pid < 0){
     23 		fprint(2, "%s: wait: %r\n", argv0);
     24 		_exit(97);
     25 	}
     26 	if(WIFEXITED(status))
     27 		 _exit(WEXITSTATUS(status));
     28 	if(WIFSIGNALED(status)){
     29 		/*
     30 		 * Make sure we don't scribble over the nice
     31 		 * core file that our child just wrote out.
     32 		 */
     33 		rl.rlim_cur = 0;
     34 		rl.rlim_max = 0;
     35 		setrlimit(RLIMIT_CORE, &rl);
     36 
     37 		signal(WTERMSIG(status), SIG_DFL);
     38 		raise(WTERMSIG(status));
     39 		_exit(98);	/* not reached */
     40 	}
     41 	if(WIFSTOPPED(status)){
     42 		fprint(2, "%s: wait pid %d stopped\n", argv0, pid);
     43 		return;
     44 	}
     45 #ifdef WIFCONTINUED
     46 	if(WIFCONTINUED(status)){
     47 		fprint(2, "%s: wait pid %d continued\n", argv0, pid);
     48 		return;
     49 	}
     50 #endif
     51 	fprint(2, "%s: wait pid %d status 0x%ux\n", argv0, pid, status);
     52 	_exit(99);
     53 }
     54 
     55 static void
     56 sigpass(int sig)
     57 {
     58 	if(sigpid == 1){
     59 		gotsigchld = 1;
     60 		return;
     61 	}
     62 
     63 	if(sig == SIGCHLD)
     64 		child();
     65 	else
     66 		kill(sigpid, sig);
     67 }
     68 
     69 static int sigs[] =
     70 {
     71 	SIGHUP, SIGINT, SIGQUIT, SIGILL,
     72 	SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
     73 	SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE,
     74 	SIGALRM, SIGTERM, SIGCHLD, SIGSTOP,
     75 	/*SIGTSTP, SIGTTIN, SIGTTOU,*/ SIGURG,
     76 	SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF,
     77 #ifdef SIGWINCH
     78 	SIGWINCH,
     79 #endif
     80 #ifdef SIGIO
     81 	SIGIO,
     82 #endif
     83 #ifdef SIGEMT
     84 	SIGEMT,
     85 #endif
     86 #ifdef SIGPWR
     87 	SIGPWR,
     88 #endif
     89 #ifdef SIGINFO
     90 	SIGINFO,
     91 #endif
     92 	SIGSYS
     93 };
     94 
     95 void
     96 _threadsetupdaemonize(void)
     97 {
     98 	int i, n, pid;
     99 	int p[2];
    100 	char buf[20];
    101 
    102 	sigpid = 1;
    103 
    104 	/*
    105 	 * We've been told this program is likely to background itself.
    106 	 * Put it in its own process group so that we don't get a SIGHUP
    107 	 * when the parent exits.
    108 	 */
    109 	setpgid(0, 0);
    110 
    111 	if(pipe(p) < 0)
    112 		sysfatal("passer pipe: %r");
    113 
    114 	/* hide these somewhere they won't cause harm */
    115 	/* can't go too high: NetBSD max is 64, for example */
    116 	if(dup(p[0], 28) < 0 || dup(p[1], 29) < 0)
    117 		sysfatal("passer pipe dup: %r");
    118 	close(p[0]);
    119 	close(p[1]);
    120 	p[0] = 28;
    121 	p[1] = 29;
    122 
    123 	/* close on exec */
    124 	if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0)
    125 		sysfatal("passer pipe pipe fcntl: %r");
    126 
    127 	noteenable("sys: child");
    128 	signal(SIGCHLD, sigpass);
    129 	switch(pid = fork()){
    130 	case -1:
    131 		sysfatal("passer fork: %r");
    132 	default:
    133 		close(p[1]);
    134 		break;
    135 	case 0:
    136 		notedisable("sys: child");
    137 		signal(SIGCHLD, SIG_DFL);
    138 	/*	rfork(RFNOTEG); */
    139 		close(p[0]);
    140 		threadpassfd = p[1];
    141 		return;
    142 	}
    143 
    144 	sigpid = pid;
    145 	if(gotsigchld)
    146 		sigpass(SIGCHLD);
    147 
    148 	for(i=0; i<nelem(sigs); i++){
    149 		struct sigaction sa;
    150 
    151 		memset(&sa, 0, sizeof sa);
    152 		sa.sa_handler = sigpass;
    153 		sa.sa_flags |= SA_RESTART;
    154 		sigaction(sigs[i], &sa, nil);
    155 	}
    156 
    157 	for(;;){
    158 		n = read(p[0], buf, sizeof buf-1);
    159 		if(n == 0){	/* program exited */
    160 			child();
    161 		}
    162 		if(n > 0)
    163 			break;
    164 		print("passer read: %r\n");
    165 	}
    166 	buf[n] = 0;
    167 	_exit(atoi(buf));
    168 }
    169 
    170 void
    171 _threaddaemonize(void)
    172 {
    173 	if(threadpassfd < 0)
    174 		sysfatal("threads in main proc exited w/o threadmaybackground");
    175 	write(threadpassfd, "0", 1);
    176 	close(threadpassfd);
    177 	threadpassfd = -1;
    178 }