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 }