void sigchld() { int wstat; int pid; while ((pid = wait_nohang(&wstat)) > 0) { fprintf(stderr, "end: pid %d status %d\n", pid, wstat); if (autokill != 0) ptable_remove(pt, limit, pid); if (numchildren) --numchildren; printstatus(); } }
void sigchld() { int wstat; int pid; while ((pid = wait_nohang(&wstat)) > 0) { if (verbosity >= 2) { errlog(0,NOTICE,B("end ",fmtnum(pid)," status ",fmtnum(wstat))); } if (numchildren) { --numchildren; } printstatus(); } }
void sigchld(void) { int wstat; int pid; while ((pid = wait_nohang(&wstat)) > 0) { if (verbosity >= 2) { strnum[fmt_ulong(strnum,pid)] = 0; strnum2[fmt_ulong(strnum2,wstat)] = 0; strerr_warn4("sslserver: end ",strnum," status ",strnum2,0); } if (numchildren) --numchildren; printstatus(); } }
void sigchld() { int wstat; int pid; int i; while ((pid = wait_nohang(&wstat)) > 0) for (i = 0; i < auto_spawn; ++i) if (d[i].used) if (d[i].pid == pid) { close(d[i].fdout); d[i].fdout = -1; d[i].wstat = wstat; d[i].pid = 0; } }
void sig_child_handler() { int wstat; int i; while ((i =wait_nohang(&wstat)) > 0) { if (phccmax) ipsvd_phcc_rem(i); if (cnum) cnum--; if (verbose) { bufnum[fmt_ulong(bufnum, i)] =0; out(INFO); out("end "); out(bufnum); out(" exit "); bufnum[fmt_ulong(bufnum, (unsigned long)wait_exitcode(wstat))] =0; out(bufnum); flush("\n"); } } if (verbose) connection_status(); }
int wait_pids_nohang (pid_t const *pids, unsigned int len, int *wstat) { for (;;) { int w ; register pid_t r = wait_nohang(&w) ; if (!r || (r == (pid_t)-1)) return (int)r ; { register unsigned int i = 0 ; for (; i < len ; i++) if (r == pids[i]) break ; if (i < len) { *wstat = w ; return 1+i ; } } } }
int main (int argc, const char * const *argv, char * const *envp) { const char * prog[2]; int pid, pid2; int wstat; int st; iopause_fd x; #ifndef IOPAUSE_POLL fd_set rfds; struct timeval t; #endif char ch; int ttyfd; struct stat s; if (getpid() != 1) strerr_die2x(111, FATAL, "must be run as process no 1."); setsid(); sig_block(sig_alarm); sig_block(sig_child); sig_catch(sig_child, sig_child_handler); sig_block(sig_cont); sig_catch(sig_cont, sig_cont_handler); sig_block(sig_hangup); sig_block(sig_int); sig_catch(sig_int, sig_int_handler); sig_block(sig_pipe); sig_block(sig_term); /* console */ if ((ttyfd =open_write("/dev/console")) != -1) { dup2(ttyfd, 0); dup2(ttyfd, 1); dup2(ttyfd, 2); if (ttyfd > 2) close(ttyfd); } /* create selfpipe */ while (pipe(selfpipe) == -1) { strerr_warn2(FATAL, "unable to create selfpipe, pausing: ", &strerr_sys); sleep(5); } coe(selfpipe[0]); coe(selfpipe[1]); ndelay_on(selfpipe[0]); ndelay_on(selfpipe[1]); #ifdef RB_DISABLE_CAD /* activate ctrlaltdel handling, glibc, dietlibc */ if (RB_DISABLE_CAD == 0) reboot_system(0); #endif strerr_warn3(INFO, "$Id: 25da3b86f7bed4038b8a039d2f8e8c9bbcf0822b $", ": booting.", 0); /* runit */ for (st =0; st < 3; st++) { /* if (st == 2) logwtmp("~", "reboot", ""); */ while ((pid =fork()) == -1) { strerr_warn4(FATAL, "unable to fork for \"", stage[st], "\" pausing: ", &strerr_sys); sleep(5); } if (!pid) { /* child */ prog[0] =stage[st]; prog[1] =0; /* stage 1 gets full control of console */ if (st == 0) { if ((ttyfd =open("/dev/console", O_RDWR)) != -1) { #ifdef TIOCSCTTY ioctl(ttyfd, TIOCSCTTY, (char *)0); #endif dup2(ttyfd, 0); if (ttyfd > 2) close(ttyfd); } else strerr_warn2(WARNING, "unable to open /dev/console: ", &strerr_sys); } else setsid(); sig_unblock(sig_alarm); sig_unblock(sig_child); sig_uncatch(sig_child); sig_unblock(sig_cont); sig_ignore(sig_cont); sig_unblock(sig_hangup); sig_unblock(sig_int); sig_uncatch(sig_int); sig_unblock(sig_pipe); sig_unblock(sig_term); strerr_warn3(INFO, "enter stage: ", stage[st], 0); execve(*prog, (char *const *)prog, envp); strerr_die4sys(0, FATAL, "unable to start child: ", stage[st], ": "); } x.fd =selfpipe[0]; x.events =IOPAUSE_READ; for (;;) { int child; sig_unblock(sig_child); sig_unblock(sig_cont); sig_unblock(sig_int); #ifdef IOPAUSE_POLL poll(&x, 1, 14000); #else t.tv_sec =14; t.tv_usec =0; FD_ZERO(&rfds); FD_SET(x.fd, &rfds); select(x.fd +1, &rfds, (fd_set*)0, (fd_set*)0, &t); #endif sig_block(sig_cont); sig_block(sig_child); sig_block(sig_int); while (read(selfpipe[0], &ch, 1) == 1) {} while ((child =wait_nohang(&wstat)) > 0) if (child == pid) break; if (child == -1) { strerr_warn2(WARNING, "wait_nohang, pausing: ", &strerr_sys); sleep(5); } /* reget stderr */ if ((ttyfd =open_write("/dev/console")) != -1) { dup2(ttyfd, 2); if (ttyfd > 2) close(ttyfd); } if (child == pid) { if (wait_exitcode(wstat) != 0) { if (wait_crashed(wstat)) strerr_warn3(WARNING, "child crashed: ", stage[st], 0); else strerr_warn3(WARNING, "child failed: ", stage[st], 0); if (st == 0) /* this is stage 1 */ if (wait_crashed(wstat) || (wait_exitcode(wstat) == 100)) { strerr_warn3(INFO, "leave stage: ", stage[st], 0); strerr_warn2(WARNING, "skipping stage 2...", 0); st++; break; } if (st == 1) /* this is stage 2 */ if (wait_crashed(wstat) || (wait_exitcode(wstat) == 111)) { strerr_warn2(WARNING, "killing all processes in stage 2...", 0); kill(-pid, 9); sleep(5); strerr_warn2(WARNING, "restarting.", 0); st--; break; } } strerr_warn3(INFO, "leave stage: ", stage[st], 0); break; } if (child != 0) { /* collect terminated children */ write(selfpipe[1], "", 1); continue; } /* sig? */ if (!sigc && !sigi) { #ifdef DEBUG strerr_warn2(WARNING, "poll: ", &strerr_sys); #endif continue; } if (st != 1) { strerr_warn2(WARNING, "signals only work in stage 2.", 0); sigc =sigi =0; continue; } if (sigi && (stat(CTRLALTDEL, &s) != -1) && (s.st_mode & S_IXUSR)) { strerr_warn2(INFO, "ctrl-alt-del request...", 0); prog[0] =CTRLALTDEL; prog[1] =0; while ((pid2 =fork()) == -1) { strerr_warn4(FATAL, "unable to fork for \"", CTRLALTDEL, "\" pausing: ", &strerr_sys); sleep(5); } if (!pid2) { /* child */ strerr_warn3(INFO, "enter stage: ", prog[0], 0); execve(*prog, (char *const *) prog, envp); strerr_die4sys(0, FATAL, "unable to start child: ", prog[0], ": "); } if (wait_pid(&wstat, pid2) == -1) strerr_warn2(FATAL, "wait_pid: ", &strerr_sys); if (wait_crashed(wstat)) strerr_warn3(WARNING, "child crashed: ", CTRLALTDEL, 0); strerr_warn3(INFO, "leave stage: ", prog[0], 0); sigi =0; sigc++; } if (sigc && (stat(STOPIT, &s) != -1) && (s.st_mode & S_IXUSR)) { int i; /* unlink(STOPIT); */ chmod(STOPIT, 0); /* kill stage 2 */ #ifdef DEBUG strerr_warn2(WARNING, "sending sigterm...", 0); #endif kill(pid, sig_term); i =0; while (i < 5) { if ((child =wait_nohang(&wstat)) == pid) { #ifdef DEBUG strerr_warn2(WARNING, "stage 2 terminated.", 0); #endif pid =0; break; } if (child) continue; if (child == -1) strerr_warn2(WARNING, "wait_nohang: ", &strerr_sys); #ifdef DEBUG strerr_warn2(WARNING, "waiting...", 0); #endif sleep(1); i++; } if (pid) { /* still there */ strerr_warn2(WARNING, "stage 2 not terminated, sending sigkill...", 0); kill(pid, 9); if (wait_pid(&wstat, pid) == -1) strerr_warn2(WARNING, "wait_pid: ", &strerr_sys); } sigc =0; strerr_warn3(INFO, "leave stage: ", stage[st], 0); /* enter stage 3 */ break; } sigc =sigi =0; #ifdef DEBUG strerr_warn2(WARNING, "no request.", 0); #endif } } /* reget stderr */ if ((ttyfd =open_write("/dev/console")) != -1) { dup2(ttyfd, 2); if (ttyfd > 2) close(ttyfd); } #ifdef RB_AUTOBOOT /* fallthrough stage 3 */ strerr_warn2(INFO, "sending KILL signal to all processes...", 0); kill(-1, SIGKILL); pid =fork(); switch (pid) { case 0: case -1: if ((stat(REBOOT, &s) != -1) && (s.st_mode & S_IXUSR)) { strerr_warn2(INFO, "system reboot.", 0); sync(); reboot_system(RB_AUTOBOOT); } else { #ifdef RB_POWER_OFF strerr_warn2(INFO, "power off...", 0); sync(); reboot_system(RB_POWER_OFF); sleep(2); #endif #ifdef RB_HALT_SYSTEM strerr_warn2(INFO, "system halt.", 0); sync(); reboot_system(RB_HALT_SYSTEM); #else #ifdef RB_HALT strerr_warn2(INFO, "system halt.", 0); sync(); reboot_system(RB_HALT); #else strerr_warn2(INFO, "system reboot.", 0); sync(); reboot_system(RB_AUTOBOOT); #endif #endif } if (pid == 0) _exit(0); break; default: sig_unblock(sig_child); while (wait_pid(0, pid) == -1); } #endif for (;;) sig_pause(); /* not reached */ strerr_die2x(0, INFO, "exit."); return(0); }
int runsvdir_main(int argc, char **argv) { struct stat s; dev_t last_dev = last_dev; /* for gcc */ ino_t last_ino = last_ino; /* for gcc */ time_t last_mtime = 0; int wstat; int curdir; int pid; unsigned deadline; unsigned now; unsigned stampcheck; char ch; int i; argv++; if (!*argv) bb_show_usage(); if (argv[0][0] == '-') { switch (argv[0][1]) { case 'P': set_pgrp = 1; case '-': ++argv; } if (!*argv) bb_show_usage(); } sig_catch(SIGTERM, s_term); sig_catch(SIGHUP, s_hangup); svdir = *argv++; if (argv && *argv) { rplog = *argv; if (setup_log() != 1) { rplog = 0; warnx("log service disabled"); } } curdir = open_read("."); if (curdir == -1) fatal2_cannot("open current directory", ""); coe(curdir); stampcheck = monotonic_sec(); for (;;) { /* collect children */ for (;;) { pid = wait_nohang(&wstat); if (pid <= 0) break; for (i = 0; i < svnum; i++) { if (pid == sv[i].pid) { /* runsv has gone */ sv[i].pid = 0; check = 1; break; } } } now = monotonic_sec(); if ((int)(now - stampcheck) >= 0) { /* wait at least a second */ stampcheck = now + 1; if (stat(svdir, &s) != -1) { if (check || s.st_mtime != last_mtime || s.st_ino != last_ino || s.st_dev != last_dev ) { /* svdir modified */ if (chdir(svdir) != -1) { last_mtime = s.st_mtime; last_dev = s.st_dev; last_ino = s.st_ino; check = 0; //if (now <= mtime) // sleep(1); runsvdir(); while (fchdir(curdir) == -1) { warn2_cannot("change directory, pausing", ""); sleep(5); } } else warn2_cannot("change directory to ", svdir); } } else warn2_cannot("stat ", svdir); } if (rplog) { if ((int)(now - stamplog) >= 0) { write(logpipe[1], ".", 1); stamplog = now + 900; } } pfd[0].revents = 0; sig_block(SIGCHLD); deadline = (check ? 1 : 5); if (rplog) poll(pfd, 1, deadline*1000); else sleep(deadline); sig_unblock(SIGCHLD); if (pfd[0].revents & POLLIN) { while (read(logpipe[0], &ch, 1) > 0) { if (ch) { for (i = 6; i < rploglen; i++) rplog[i-1] = rplog[i]; rplog[rploglen-1] = ch; } } } switch (exitsoon) { case 1: _exit(0); case 2: for (i = 0; i < svnum; i++) if (sv[i].pid) kill(sv[i].pid, SIGTERM); _exit(111); } } /* not reached */ return 0; }
int main(int argc, char **argv) { struct stat s; time_t mtime =0; int wstat; int curdir; int pid; struct taia deadline; struct taia now; struct taia stampcheck; char ch; int i; progname =*argv++; if (! argv || ! *argv) usage(); if (**argv == '-') { switch (*(*argv +1)) { case 'P': pgrp =1; case '-': ++argv; } if (! argv || ! *argv) usage(); } sig_catch(sig_term, s_term); sig_catch(sig_hangup, s_hangup); svdir =*argv++; if (argv && *argv) { rplog =*argv; if (setup_log() != 1) { rplog =0; warn3x("log service disabled.", 0, 0); } } if ((curdir =open_read(".")) == -1) fatal("unable to open current directory", 0); coe(curdir); taia_now(&stampcheck); for (;;) { /* collect children */ for (;;) { if ((pid =wait_nohang(&wstat)) <= 0) break; for (i =0; i < svnum; i++) { if (pid == sv[i].pid) { /* runsv has gone */ sv[i].pid =0; check =1; break; } } } taia_now(&now); if (now.sec.x < (stampcheck.sec.x -3)) { /* time warp */ warn3x("time warp: resetting time stamp.", 0, 0); taia_now(&stampcheck); taia_now(&now); if (rplog) taia_now(&stamplog); } if (taia_less(&now, &stampcheck) == 0) { /* wait at least a second */ taia_uint(&deadline, 1); taia_add(&stampcheck, &now, &deadline); if (stat(svdir, &s) != -1) { if (check || \ s.st_mtime != mtime || s.st_ino != ino || s.st_dev != dev) { /* svdir modified */ if (chdir(svdir) != -1) { mtime =s.st_mtime; dev =s.st_dev; ino =s.st_ino; check =0; if (now.sec.x <= (4611686018427387914ULL +(uint64)mtime)) sleep(1); runsvdir(); while (fchdir(curdir) == -1) { warn("unable to change directory, pausing", 0); sleep(5); } } else warn("unable to change directory to ", svdir); } } else warn("unable to stat ", svdir); } if (rplog) if (taia_less(&now, &stamplog) == 0) { write(logpipe[1], ".", 1); taia_uint(&deadline, 900); taia_add(&stamplog, &now, &deadline); } /* half a second */ deadline.sec.x =0; deadline.nano =500000000UL; deadline.atto =0; taia_add(&deadline, &now, &deadline); sig_block(sig_child); if (rplog) iopause(io, 1, &deadline, &now); else iopause(0, 0, &deadline, &now); sig_unblock(sig_child); if (rplog && (io[0].revents | IOPAUSE_READ)) while (read(logpipe[0], &ch, 1) > 0) if (ch) { for (i =6; i < rploglen; i++) rplog[i -1] =rplog[i]; rplog[rploglen -1] =ch; } switch(exitsoon) { case 1: _exit(0); case 2: for (i =0; i < svnum; i++) if (sv[i].pid) kill(sv[i].pid, SIGTERM); _exit(111); } } /* for (;;) */ /* not reached */ _exit(0); }
void doit(int t) { int fakev4=0; int j; SSL *ssl; int wstat; uint32 scope_id; int sslctl[2]; char *s; unsigned long tmp_long; char sslctl_cmd; stralloc ssl_env = { 0 }; buffer ssl_env_buf; if (pipe(pi) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (pipe(po) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sslctl) == -1) strerr_die2sys(111,DROP,"unable to create socketpair: "); switch(fork()) { case -1: strerr_die2sys(111,DROP,"unable to fork: "); case 0: /* Child */ break; default: /* Parent */ close(pi[0]); close(po[1]); close(sslctl[1]); if ((s=env_get("SSL_CHROOT"))) if (chroot(s) == -1) strerr_die2x(111,DROPSSL,"unable to chroot"); if ((s=env_get("SSL_GID"))) { scan_ulong(s,&tmp_long); gid = tmp_long; } if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,DROPSSL,"unable to set gid: "); if ((s=env_get("SSL_UID"))) { scan_ulong(s,&tmp_long); uid = tmp_long; } if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,DROPSSL,"unable to set uid: "); /* This will exit on a fatal error or if the client quits * without activating SSL */ sslctl_cmd = ucspitls_master_wait_for_activation(sslctl[0]); /* If we got here, SSL must have been activated */ ssl = ssl_new(ctx,t); if (!ssl) strerr_die2x(111,DROP,"unable to create SSL instance"); if (ndelay_on(t) == -1) strerr_die2sys(111,DROP,"unable to set socket options: "); if (ssl_timeoutaccept(ssl,ssltimeout) == -1) strerr_die3x(111,DROP,"unable to accept SSL: ",ssl_error_str(ssl_errno)); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn3("sslserver: ssl ",strnum," accept ",0); } if (flagclientcert) { switch(ssl_verify(ssl,verifyhost)) { case -1: strerr_die2x(111,DROP,"unable to verify client certificate"); case -2: strerr_die2x(111,DROP,"no client certificate"); case -3: strerr_die2x(111,DROP,"client name does not match certificate"); default: break; } } if (sslctl_cmd == 'Y') { ssl_server_env(ssl, &ssl_env); stralloc_0(&ssl_env); /* Add another NUL */ buffer_init(&ssl_env_buf,buffer_unixwrite,sslctl[0],NULL,0); if (buffer_putflush(&ssl_env_buf, ssl_env.s, ssl_env.len) == -1) { strerr_die2sys(111, FATAL, "unable to write SSL environment: "); } } else if (sslctl_cmd != 'y') { strerr_die2x(111,DROP,"Protocol error on SSL control descriptor: invalid command character read"); } if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (ssl_io(ssl,pi[1],po[0],io_opt) != 0) strerr_die3x(111,DROP,"unable to speak SSL: ",ssl_error_str(ssl_errno)); if (wait_nohang(&wstat) > 0) _exit(wait_exitcode(wstat)); ssl_close(ssl); _exit(0); } /* Child-only below this point */ if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; else remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn4("sslserver: pid ",strnum," from ",remoteipstr,0); } if (socket_local6(t,localip,&localport,&scope_id) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); if (fakev4) localipstr[ip4_fmt(localipstr,localip+12)] = 0; else localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name6(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } env("PROTO",fakev4?"SSL":"SSL6"); env("SSLLOCALIP",localipstr); env("SSL6LOCALIP",localipstr); env("SSLLOCALPORT",localportstr); env("SSL6LOCALPORT",localportstr); env("SSLLOCALHOST",localhost); env("SSL6LOCALHOST",localhost); if (!fakev4 && scope_id) env("SSL6INTERFACE",socket_getifname(scope_id)); if (flagtcpenv) { env("TCPLOCALIP",localipstr); env("TCP6LOCALIP",localipstr); env("TCPLOCALPORT",localportstr); env("TCP6LOCALPORT",localportstr); env("TCPLOCALHOST",localhost); env("TCP6LOCALHOST",localhost); if (!fakev4 && scope_id) env("TCP6INTERFACE",socket_getifname(scope_id)); } if (flagremotehost) if (dns_name6(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) { verifyhost = remoteipstr; if (dns_ip6(&tmp,&remotehostsa) == 0) for (j = 0;j + 16 <= tmp.len;j += 16) if (byte_equal(remoteip,16,tmp.s + j)) { flagparanoid = 0; break; } } if (!flagparanoid) { if (!stralloc_0(&remotehostsa)) drop_nomem(); remotehost = remotehostsa.s; verifyhost = remotehostsa.s; } } env("SSLREMOTEIP",remoteipstr); env("SSL6REMOTEIP",remoteipstr); remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0; env("SSLREMOTEPORT",remoteportstr); env("SSL6REMOTEPORT",remoteportstr); env("SSLREMOTEHOST",remotehost); env("SSL6REMOTEHOST",remotehost); if (flagtcpenv) { env("TCPREMOTEIP",remoteipstr); env("TCP6REMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); env("TCP6REMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); env("TCP6REMOTEHOST",remotehost); } if (flagremoteinfo) { if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); } env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("SSL6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (flagtcpenv) { env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); } if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { int fakev4=0; char* temp; if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) temp=remoteipstr+7; else temp=remoteipstr; if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"sslserver: ")) drop_nomem(); safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipstr); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipstr); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,FATAL,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,FATAL,"unable to set uid: "); close(pi[1]); close(po[0]); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); if (fcntl(sslctl[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,sslctl[1])]=0; setenv("SSLCTLFD",strnum,1); if (fcntl(pi[0],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,pi[0])]=0; setenv("SSLREADFD",strnum,1); if (fcntl(po[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,po[1])]=0; setenv("SSLWRITEFD",strnum,1); if (flagsslwait) { if (fd_copy(0,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_copy(1,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } else { if (fd_move(0,pi[0]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_move(1,po[1]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } if (flagkillopts) socket_ipoptionskill(t); if (!flagdelay) socket_tcpnodelay(t); if (*banner) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); if (buffer_putsflush(&b,banner) == -1) strerr_die2sys(111,DROP,"unable to print banner: "); } if (!flagsslwait) { strnum[fmt_ulong(strnum,flagsslenv)] = 0; strerr_warn2("flagsslenv: ", strnum, 0); ucspitls(flagsslenv,0,1); } pathexec(prog); strerr_die4sys(111,DROP,"unable to run ",*prog,": "); }
void doit(int t) { int j; SSL *ssl; int wstat; int sslctl[2]; char *s; unsigned long tmp_long; char ssl_cmd; stralloc ssl_env = { 0 }; int bytesleft; char envbuf[8192]; int childpid; if (pipe(pi) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (pipe(po) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sslctl) == -1) strerr_die2sys(111,DROP,"unable to create socketpair: "); if ((j = ip_fmt(&remoteipsa,&remoteaddr))) strerr_die3x(111,DROP,"unable to print remote ip",gai_strerror(j)); if (flagremotehost) { if (dns_name(&remotehostsa,&remoteaddr) == 0) if (remotehostsa.len) { if (flagparanoid) { struct addrinfo *reverse, hints = {0}; verifyhost = remoteipsa.s; hints.ai_family = remoteaddr.sa4.sin_family; if (remoteaddr.sa6.sin6_family == AF_INET6) { hints.ai_flags = AI_V4MAPPED | AI_ALL; } if (getaddrinfo(remotehostsa.s, NULL, &hints, &reverse) == 0) { hints.ai_next = reverse; while (hints.ai_next) { if (hints.ai_next->ai_family == AF_INET && remoteaddr.sa4.sin_family == AF_INET && byte_equal(&remoteaddr.sa4.sin_addr, 4, &((struct sockaddr_in*) hints.ai_next->ai_addr)->sin_addr) || hints.ai_next->ai_family == AF_INET6 && remoteaddr.sa6.sin6_family == AF_INET6 && byte_equal(remoteaddr.sa6.sin6_addr.s6_addr, 16, &((struct sockaddr_in6*) hints.ai_next->ai_addr)->sin6_addr.s6_addr)) { flagparanoid = 0; break; } hints.ai_next = hints.ai_next->ai_next; } freeaddrinfo(reverse); } } if (!flagparanoid) { remotehost = remotehostsa.s; verifyhost = remotehostsa.s; } } } switch(childpid=fork()) { case -1: strerr_die2sys(111,DROP,"unable to fork: "); case 0: /* Child */ close(sslctl[0]); break; default: /* Parent */ close(pi[0]); close(po[1]); close(sslctl[1]); if ((s=env_get("SSL_CHROOT"))) if (chroot(s) == -1) { kill(childpid, SIGTERM); strerr_die2x(111,DROP,"unable to chroot"); } if ((s=env_get("SSL_GID"))) { scan_ulong(s,&tmp_long); gid = tmp_long; } if (gid) if (prot_gid(gid) == -1) { kill(childpid, SIGTERM); strerr_die2sys(111,FATAL,"unable to set gid: "); } if ((s=env_get("SSL_UID"))) { scan_ulong(s,&tmp_long); uid = tmp_long; } if (uid) if (prot_uid(uid) == -1) { kill(childpid, SIGTERM); strerr_die2sys(111,FATAL,"unable to set uid: "); } /* Read the TLS command socket. This will block until/unless * TLS is requested. */ if (read(sslctl[0],&ssl_cmd,1) == 1) { ssl = ssl_new(ctx,t); if (!ssl) { kill(childpid, SIGTERM); strerr_die2x(111,DROP,"unable to create SSL instance"); } if (ndelay_on(t) == -1) { kill(childpid, SIGTERM); strerr_die2sys(111,DROP,"unable to set socket options: "); } if (ssl_timeoutaccept(ssl,ssltimeout) == -1) { kill(childpid, SIGTERM); strerr_die3x(111,DROP,"unable to accept SSL: ",ssl_error_str(ssl_errno)); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn3("sslserver: ssl ",strnum," accept ",0); } if (flagclientcert) { switch(ssl_verify(ssl,verifyhost)) { case -1: kill(childpid, SIGTERM); strerr_die2x(111,DROP,"unable to verify client certificate"); case -2: kill(childpid, SIGTERM); strerr_die2x(111,DROP,"no client certificate"); case -3: kill(childpid, SIGTERM); strerr_die3x(111,DROP,"certificate name does not match client fqdn: ",verifyhost); default: break; } } if (ssl_cmd == 'Y') { ssl_server_env(ssl, &ssl_env); if(!stralloc_0(&ssl_env)) drop_nomem(); /* Add another NUL */ env("SSLCTL",ssl_env.s); for(bytesleft = ssl_env.len; bytesleft>0; bytesleft-=j) if ( (j=write(sslctl[0], ssl_env.s, bytesleft)) < 0) { kill(childpid, SIGTERM); strerr_die2sys(111, FATAL, "unable to write SSL environment: "); } } if (ssl_cmd == 'Y' || ssl_cmd == 'y') { if (ssl_io(ssl,pi[1],po[0],progtimeout) != 0) { kill(childpid, SIGTERM); strerr_die3x(111,DROP,"unable to speak SSL: ",ssl_error_str(ssl_errno)); } if (wait_nohang(&wstat) > 0) _exit(wait_exitcode(wstat)); ssl_close(ssl); } kill(childpid, SIGTERM); _exit(0); } /* Child-only below this point */ if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn4("sslserver: pid ",strnum," from ",remoteipsa.s,0); } if (socket_local(t,&localaddr,&localport) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); if ((j = ip_fmt(&localipsa,&localaddr))) strerr_die3x(111,DROP,"unable to print local address: ",gai_strerror(j)); remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name(&localhostsa,&localaddr) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } /* If remoteipsa.s contain ':' colon character will assume it is IPv6 */ if (byte_chr(remoteipsa.s, remoteipsa.len, ':') < remoteipsa.len) env("PROTO","SSL6"); else env("PROTO","SSL"); env("SSLLOCALIP",localipsa.s); env("SSLLOCALPORT",localportstr); env("SSLLOCALHOST",localhost); if (flagtcpenv) { env("TCPLOCALIP",localipsa.s); env("TCPLOCALPORT",localportstr); env("TCPLOCALHOST",localhost); } env("SSLREMOTEIP",remoteipsa.s); env("SSLREMOTEPORT",remoteportstr); env("SSLREMOTEHOST",remotehost); if (flagtcpenv) { env("TCPREMOTEIP",remoteipsa.s); env("TCPREMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); } if (flagremoteinfo) { if (remoteinfo(&tcpremoteinfo,&remoteaddr,&localaddr,timeout) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); } env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (flagtcpenv) env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { if (rules(found,fdrules,&remoteaddr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"sslserver: ")) drop_nomem(); safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipsa.s); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipsa.s); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,FATAL,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,FATAL,"unable to set uid: "); close(pi[1]); close(po[0]); close(sslctl[0]); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); if (fcntl(sslctl[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,sslctl[1])]=0; env("SSLCTLFD",strnum); if (fcntl(pi[0],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,pi[0])]=0; env("SSLREADFD",strnum); if (fcntl(po[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,po[1])]=0; env("SSLWRITEFD",strnum); if (flagsslwait) { if (fd_copy(0,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_copy(1,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } else { if (fd_move(0,pi[0]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_move(1,po[1]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } if (flagkillopts) socket_ipoptionskill(t); if (!flagdelay) socket_tcpnodelay(t); if (*banner) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); if (buffer_putsflush(&b,banner) == -1) strerr_die2sys(111,DROP,"unable to print banner: "); } if (!flagsslwait) { ssl_cmd = flagsslenv ? 'Y' : 'y'; if (write(sslctl[1], &ssl_cmd, 1) < 1) strerr_die2sys(111,DROP,"unable to start SSL: "); if (flagsslenv) { while ((j=read(sslctl[1],envbuf,8192)) > 0) { stralloc_catb(&ssl_env,envbuf,j); if (ssl_env.len >= 2 && ssl_env.s[ssl_env.len-2]==0 && ssl_env.s[ssl_env.len-1]==0) break; } if (j < 0) strerr_die2sys(111,DROP,"unable to read SSL environment: "); pathexec_multienv(&ssl_env); } } pathexec(prog); strerr_die4sys(111,DROP,"unable to run ",*prog,": "); }
static void reap (void) { tain_t nextscan ; if (!wantreap) return ; wantreap = 0 ; tain_addsec_g(&nextscan, 1) ; for (;;) { int wstat ; int r = wait_nohang(&wstat) ; if (r < 0) if (errno != ECHILD) panic("wait_nohang") ; else break ; else if (!r) break ; else { register unsigned int i = 0 ; for (; i < n ; i++) { if (services[i].pid[0] == r) { services[i].pid[0] = 0 ; services[i].restartafter[0] = nextscan ; break ; } else if (services[i].pid[1] == r) { services[i].pid[1] = 0 ; services[i].restartafter[1] = nextscan ; break ; } } if (i == n) continue ; if (services[i].flagactive) { if (tain_less(&nextscan, &deadline)) deadline = nextscan ; } else { if (services[i].flaglog) { /* BLACK MAGIC: - we need to close the pipe early: * as soon as the writer exits so the logger can exit on EOF * or as soon as the logger exits so the writer can crash on EPIPE - but if the same service gets reactivated before the second supervise process exits, ouch: we've lost the pipe - so we can't reuse the same service even if it gets reactivated - so we're marking a dying service with a closed pipe - if the scanner sees a service with p[0] = -1 it won't flag it as active (and won't restart the dead supervise) - but if the service gets reactivated we want it to restart as soon as the 2nd supervise process dies - so the scanner marks such a process with p[0] = -2 - and the reaper triggers a scan when it finds a -2. */ if (services[i].p[0] >= 0) { fd_close(services[i].p[1]) ; services[i].p[1] = -1 ; fd_close(services[i].p[0]) ; services[i].p[0] = -1 ; } else if (services[i].p[0] == -2) wantscan = 1 ; } if (!services[i].pid[0] && (!services[i].flaglog || !services[i].pid[1])) services[i] = services[--n] ; } } } }
void doit(void) { iopause_fd x[2]; struct taia deadline; struct taia stamp; int wstat; int r; char ch; announce(); for (;;) { if (flagexit && !pid) return; sig_unblock(sig_child); x[0].fd = selfpipe[0]; x[0].events = IOPAUSE_READ; x[1].fd = fdcontrol; x[1].events = IOPAUSE_READ; taia_now(&stamp); taia_uint(&deadline,3600); taia_add(&deadline,&stamp,&deadline); iopause(x,2,&deadline,&stamp); sig_block(sig_child); while (read(selfpipe[0],&ch,1) == 1) ; for (;;) { r = wait_nohang(&wstat); if (!r) break; if ((r == -1) && (errno != error_intr)) break; if (r == pid) { pid = 0; pidchange(); announce(); if (flagexit) return; if (flagwant && flagwantup) trystart(); break; } } if (read(fdcontrol,&ch,1) == 1) switch(ch) { case 'd': flagwant = 1; flagwantup = 0; if (pid) { kill(pid,SIGTERM); kill(pid,SIGCONT); flagpaused = 0; } announce(); break; case 'u': flagwant = 1; flagwantup = 1; announce(); if (!pid) trystart(); break; case 'o': flagwant = 0; announce(); if (!pid) trystart(); break; case 'a': if (pid) kill(pid,SIGALRM); break; case 'h': if (pid) kill(pid,SIGHUP); break; case 'k': if (pid) kill(pid,SIGKILL); break; case 't': if (pid) kill(pid,SIGTERM); break; case 'i': if (pid) kill(pid,SIGINT); break; case 'p': flagpaused = 1; announce(); if (pid) kill(pid,SIGSTOP); break; case 'c': flagpaused = 0; announce(); if (pid) kill(pid,SIGCONT); break; case 'x': flagexit = 1; announce(); break; } } }
static void doit() { iopause_fd x[2]; struct taia deadline; struct taia stamp; int wstat; long int time_cmp = 0; int r; char ch; char warn_message[2048]; int coredumped = 0; char restart_cmd[2048]; announce(); x[0].fd = selfpipe[0]; x[0].events = IOPAUSE_READ; x[1].fd = fdcontrol; x[1].events = IOPAUSE_READ; while (1) { if (flagexit && !pid) break; taia_now(&stamp); taia_uint(&deadline, 3600); taia_add(&deadline, &stamp, &deadline); sig_unblock(sig_child); iopause(x, 2, &deadline, &stamp); sig_block(sig_child); while (read(selfpipe[0], &ch, 1) == 1); while (1) { //waitpid(-1,&wstat,WNOHANG);WNOHANG : return immediately if no child has exited r = wait_nohang(&wstat); //r==0 if one or more child(ren) exit(s) but have not yet changed state if (!r) break; //r == -1 && errno == error_intr means waitpid is interrupted by a signal, we should call waitpid again. //here is not necessary cause we call waitpid with a WNOHANG argument. if (r == -1 && errno != error_intr) break; if (r == pid) { pid = 0; pidchange(); announce(); time_now = time((time_t *)0); if(time_old) { time_cmp = time_now - time_old; if(time_cmp >= time_alarm) //cmp { num = 0; } time_old = time_now; } else { time_cmp = 0; time_old = time_now; } if (0 != restart_sh[0]) { if (num == INT_MAX) num = 0; num++; if (snprintf(restart_cmd, sizeof(restart_cmd), "%s %d", restart_sh, num) > 1) { system(restart_cmd); write_log(fdlog, NOTICE, "restart_cmd: ", restart_cmd, " is called.\n"); } } else { if (WCOREDUMP(wstat)) { have_coredumped++; coredumped = 1; } bzero(warn_message, 2048); create_warn_message(warn_message, coredumped); write_log(fdlog, NOTICE, "service exited", coredumped ? " with coredump" : "", "!\n"); coredumped = 0; if (!closealarm && alarm_interval > 0 && have_tried++ == 0) { alarm(alarm_interval); do_alarm(warn_message); } if (flagexit || (alarm_interval > 0 && have_tried > max_tries && max_tries > 0) || (alarm_interval > 0 && have_coredumped > max_tries_if_coredumped && max_tries_if_coredumped > 0)) { write_log(fdlog, NOTICE, "supervise refused to restart ", service, " any more and exited itself!\n"); alarm(0); return; } } if (flagwant && flagwantup) { write_log(fdlog, NOTICE, "supervise is trying to restart ", service, "...\n"); trystart(); } break; } } if (read(fdcontrol, &ch, 1) != 1) continue; switch(ch) { // -s: Silent. Do not alarm any more. case 's': closealarm = 1; announce(); break; case 'n': closealarm = 0; announce(); break; case 'r': parse_conf(); break; // -d: Down. If the service is running, send it a TERM signal and then a CONT signal. // After it stops, do not restart it. case 'd': flagwant = 1; flagwantup = 0; if (pid) { kill(pid, SIGTERM); kill(pid, SIGCONT); flagpaused = 0; } announce(); break; // -u: Up. If the service is not running, start it. If the service stops, restart it. case 'u': flagwant = 1; flagwantup = 1; announce(); if (!pid) trystart(); break; // -o: Once. If the service is not running, start it. Do not restart it if it stops. case 'o': flagwant = 0; announce(); if (!pid) trystart(); break; // -a: Alarm. Send the service an ALRM signal. case 'a': if (pid) kill(pid, SIGALRM); break; // -h: Hangup. Send the service a HUP signal. case 'h': if (pid) kill(pid, SIGHUP); break; // -k: Kill. Send the service a KILL signal. case 'k': if (pid) kill(pid, SIGKILL); break; //* -t: Terminate. Send the service a TERM signal. case 't': if (pid) kill(pid, SIGTERM); break; // -i: Interrupt. Send the service an INT signal. case 'i': if (pid) kill(pid, SIGINT); break; // -p: Pause. Send the service a STOP signal. case 'p': flagpaused = 1; announce(); if (pid) kill(pid, SIGSTOP); break; // -c: Continue. Send the service a CONT signal. case 'c': flagpaused = 0; announce(); if (pid) kill(pid, SIGCONT); break; // -x: Exit. supervise will exit as soon as the service is down. If you use this option on a //stable system, you're doing something wrong; supervise is designed to run forever. case 'x': flagexit = 1; announce(); break; } //end switch } //end while }