int flushread(int fd,char *buf,int len) { int j; for (j = 0;j < cnum;++j) buffer_flush(&c[j].ss); if (flagforcerotate) { for (j = 0;j < cnum;++j) if (c[j].bytes > 0) fullcurrent(&c[j]); flagforcerotate = 0; } if (!len) return 0; if (flagexitasap) { if (flagnewline) return 0; len = 1; } sig_unblock(sig_term); sig_unblock(sig_alarm); len = read(fd,buf,len); sig_block(sig_term); sig_block(sig_alarm); if (len <= 0) return len; flagnewline = (buf[len - 1] == '\n'); return len; }
int main(int argc,char **argv) { struct stat st; dir = argv[1]; if (!dir || argv[2]) strerr_die1x(100,"supervise: usage: supervise dir"); if (pipe(selfpipe) == -1) strerr_die4sys(111,FATAL,"unable to create pipe for ",dir,": "); coe(selfpipe[0]); coe(selfpipe[1]); ndelay_on(selfpipe[0]); ndelay_on(selfpipe[1]); sig_block(sig_child); sig_catch(sig_child,trigger); if (chdir(dir) == -1) strerr_die4sys(111,FATAL,"unable to chdir to ",dir,": "); if (stat("down",&st) != -1) flagwantup = 0; else if (errno != error_noent) strerr_die4sys(111,FATAL,"unable to stat ",dir,"/down: "); mkdir("supervise",0700); fdlock = open_append("supervise/lock"); if ((fdlock == -1) || (lock_exnb(fdlock) == -1)) strerr_die4sys(111,FATAL,"unable to acquire ",dir,"/supervise/lock: "); coe(fdlock); fifo_make("supervise/control",0600); fdcontrol = open_read("supervise/control"); if (fdcontrol == -1) strerr_die4sys(111,FATAL,"unable to read ",dir,"/supervise/control: "); coe(fdcontrol); ndelay_on(fdcontrol); /* shouldn't be necessary */ fdcontrolwrite = open_write("supervise/control"); if (fdcontrolwrite == -1) strerr_die4sys(111,FATAL,"unable to write ",dir,"/supervise/control: "); coe(fdcontrolwrite); pidchange(); announce(); fifo_make("supervise/ok",0600); fdok = open_read("supervise/ok"); if (fdok == -1) strerr_die4sys(111,FATAL,"unable to read ",dir,"/supervise/ok: "); coe(fdok); if (!flagwant || flagwantup) trystart(); doit(); announce(); _exit(0); }
/* forks off a job * ----------------------------------------------------------------------- */ int job_fork(struct job *job, union node *node, int bgnd) { pid_t pid; pid_t pgrp; sig_block(); /* fork the process */ if((pid = fork()) == -1) { sh_error("fork failed"); return -1; } /* in the child, set the process group and return */ if(pid == 0) { sh_forked(); if(job && job->nproc) pgrp = job->procs[0].pid; else pgrp = sh_pid; setpgid(sh_pid, pgrp); if(fd_ok(job_terminal)) /* and then give the child terminal access */ if(!bgnd) tcsetpgrp(job_terminal, pgrp); return pid; } pgrp = pid; /* in the parent update the process list of the job */ if(job) { struct proc *proc = &job->procs[job->nproc]; proc->pid = pid; proc->status = -1; if(job->nproc == 0) job->pgrp = pgrp; else pgrp = job->procs[0].pid; job->nproc++; } if(pgrp != job_pgrp && !bgnd) { if(fd_ok(job_terminal)) tcsetpgrp(job_terminal, pid); job_pgrp = pid; } return pid; }
int main() { int i; sig_catch(SIGUSR1, sigusr1_handler); sig_block(SIGUSR1); sig_unblock(SIGUSR1); for (i = 0; i < 3; i++) sleep(3); return 1; }
int main(int argc,char **argv) { umask(022); fdstartdir = open_read("."); if (fdstartdir == -1) strerr_die2sys(111,FATAL,"unable to switch to current directory: "); coe(fdstartdir); sig_block(sig_term); sig_block(sig_alarm); sig_catch(sig_term,exitasap); sig_catch(sig_alarm,forcerotate); ++argv; f_init(argv); c_init(argv); doit(argv); c_quit(); _exit(0); }
int supervise_run(void) { g_pid = 0; g_flagexit = 0; g_flagwant = 1; g_flagwantup = opt_auto_start; g_flagpaused = 0; sig_block(SIGCHLD); sig_catch(SIGCHLD, sigchild_handler); stat_pidchange(); stat_update(); if(g_flagwant && g_flagwantup) { trystart(); } while(1) { char c; ssize_t rl; if(g_flagexit && !g_pid) { return 0; } printf("waiting pid pid=%d\n",g_pid); while(1) { int stat; int r = waitpid(-1, &stat, WNOHANG); if(r == 0) { break; } if(r < 0 && errno != EAGAIN && errno != EINTR) { break; } if(r == g_pid) { g_pid = 0; stat_pidchange(); stat_update(); if(g_flagexit) { return 0; } if(g_flagwant && g_flagwantup) { trystart(); break; } } } printf("reading... pid=%d\n",g_pid); sig_unblock(SIGCHLD); rl = read(g_ctl_rfd, &c, 1); if(rl <= 0) { if(errno == EAGAIN || errno == EINTR) { continue; } return -1; } sig_block(SIGCHLD); switch(c) { case 'd': /* down */ printf("down %d\n",g_pid); g_flagwant = 1; g_flagwantup = 0; if(g_pid) { kill(g_pid, SIGTERM); kill(g_pid, SIGCONT); g_flagpaused = 0; } stat_update(); break; case 'u': /* up */ printf("up %d\n",g_pid); g_flagwant = 1; g_flagwantup = 1; if(!g_pid) { trystart(); } stat_update(); break; case 'o': /* once */ printf("once %d\n",g_pid); g_flagwant = 0; if(!g_pid) { trystart(); } stat_update(); break; case 'x': /* exit */ printf("exit %d\n",g_pid); g_flagexit = 1; stat_update(); break; case 'p': /* pause */ printf("pause %d\n",g_pid); g_flagpaused = 1; if(g_pid) { kill(g_pid, SIGSTOP); } stat_update(); break; case 'c': /* continue */ printf("continue %d\n",g_pid); g_flagpaused = 0; if(g_pid) { kill(g_pid, SIGCONT); } stat_update(); break; case 'h': /* hup */ printf("hup %d\n",g_pid); if(g_pid) { kill(g_pid, SIGHUP); } break; case 'a': /* alarm */ printf("alarm %d\n",g_pid); if(g_pid) { kill(g_pid, SIGALRM); } break; case 'i': /* interrupt */ printf("interrupt %d\n",g_pid); if(g_pid) { kill(g_pid, SIGINT); } break; case 't': /* term */ printf("term %d\n",g_pid); if(g_pid) { kill(g_pid, SIGTERM); } break; case 'k': /* kill */ printf("kill %d\n",g_pid); if(g_pid) { kill(g_pid, SIGKILL); } break; case '1': /* usr1 */ printf("usr1 %d\n",g_pid); if(g_pid) { kill(g_pid, SIGUSR1); } break; case '2': /* usr2 */ printf("usr2 %d\n",g_pid); if(g_pid) { kill(g_pid, SIGUSR2); } break; case 's': /* sigchld */ printf("sigchld %d\n",g_pid); if(!opt_auto_restart) { g_flagwant = 0; stat_update(); } break; case ' ': /* ping */ // FIXME touch status file break; } } }
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); }
/* p-adic logarithm */ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) { /* Compute the p-adic logarithm of a, which is supposed to be congruent to 1 mod p Algorithm: 1. we raise a at the power p^(v-1) (for a suitable v) in order to make it closer to 1 2. we write the new a as a product 1/a = (1 - a_0*p^v) (1 - a_1*p^(2*v) (1 - a_2*p^(4*v) ... with 0 <= a_i < p^(v*2^i). 3. we compute each log(1 - a_i*p^(v*2^i)) using Taylor expansion and a binary spliting strategy. */ unsigned long i, v, e, N, saveN, Np, tmp, trunc, step; double den = log(p); mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, mpz_tmp2, d, inv, mod2; mpz_t *num, *denom; mpz_init(mpz_tmp); mpz_init(mpz_tmp2); mpz_init(arg); mpz_set_ui(ans, 0); mpz_fdiv_r_ui(mpz_tmp, a, p); mpz_set(arg, a); /* First we make the argument closer to 1 by raising it to the p^(v-1) */ if (prec < p) { v = 0; e = 1; } else { v = (unsigned long)(log(prec)/den); // v here is v-1 e = pow(p,v); mpz_mul_ui(mpz_tmp, modulo, e); mpz_powm_ui(arg, arg, e, mpz_tmp); prec += v; } /* Where do we need to truncate the Taylor expansion */ N = prec+v; N /= ++v; // note the ++v Np = N; den *= v; while(1) { tmp = Np + (unsigned long)(log(N)/den); if (tmp == N) break; N = tmp; } /* We allocate memory and initialize variables */ mpz_init(f); mpz_init(mod2); mpz_init(h); mpz_init(hpow); mpz_init(d); mpz_init(inv); sig_block(); num = (mpz_t*)malloc(N*sizeof(mpz_t)); denom = (mpz_t*)malloc(N*sizeof(mpz_t)); sig_unblock(); for (i = 0; i < N; i++) { mpz_init(num[i]); mpz_init(denom[i]); } trunc = v << 1; mpz_init(trunc_mod); mpz_ui_pow_ui(trunc_mod, p, trunc); while(1) { /* We compute f = 1 - a_i*p^((v+1)*2^i) trunc_mod is p^((v+1)*2^(i+1)) */ mpz_fdiv_r(f, arg, trunc_mod); if (mpz_cmp_ui(f, 1) != 0) { mpz_ui_sub(f, 2, f); mpz_mul(arg, arg, f); /* We compute the Taylor expansion of log(f) For now, computations are carried out over the rationals */ for (i = 0; i < N; i++) { mpz_set_ui(num[i], 1); mpz_set_ui(denom[i], i+1); } step = 1; mpz_ui_sub(h, 1, f); // we write f = 1 - h, i.e. h = a_i*p^(2^i) mpz_set(hpow, h); while(step < N) { for (i = 0; i < N - step; i += step << 1) { mpz_mul(mpz_tmp2, hpow, num[i+step]); mpz_mul(mpz_tmp, mpz_tmp2, denom[i]); mpz_mul(num[i], num[i], denom[i+step]); mpz_add(num[i], num[i], mpz_tmp); mpz_mul(denom[i], denom[i], denom[i+step]); } step <<= 1; mpz_mul(hpow, hpow, hpow); } /* We simplify the fraction */ Np = N; tmp = 0; while(Np > 0) { Np /= p; tmp += Np; } mpz_ui_pow_ui(d, p, tmp); mpz_divexact(mpz_tmp, num[0], d); mpz_divexact(denom[0], denom[0], d); mpz_divexact_ui(h, h, e); mpz_mul(mpz_tmp, h, mpz_tmp); /* We coerce the result from Q to Zp */ mpz_gcdext(d, inv, NULL, denom[0], modulo); mpz_mul(mpz_tmp, mpz_tmp, inv); /* We add this contribution to log(f) */ mpz_add(ans, ans, mpz_tmp); } if (trunc > prec) break; /* We update the variables for the next step */ mpz_mul(trunc_mod, trunc_mod, trunc_mod); trunc <<= 1; for (i = N >> 1; i < N; i++) { mpz_clear(num[i]); mpz_clear(denom[i]); } N >>= 1; } mpz_fdiv_r(ans, ans, modulo); /* We clear memory */ mpz_clear(arg); mpz_clear(f); mpz_clear(trunc_mod); mpz_clear(h); mpz_clear(hpow); mpz_clear(mpz_tmp); mpz_clear(d); mpz_clear(inv); mpz_clear(mod2); for (i = 0; i < N; i++) { mpz_clear(num[i]); mpz_clear(denom[i]); } sig_block(); free(num); free(denom); sig_unblock(); }
int main(int argc,char * const *argv) { const char *hostname; int opt; struct servent *se; char *x; unsigned long u; int s; int t; io_opt = ssl_io_opt_default; io_opt.timeout = 3600; while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:T:u:g:l:b:B:c:Z:pPoO3IiEeSsaAw:nNyYuUjJ")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; case 'X': flagallownorules = 1; break; case 'x': fnrules = optarg; break; case 'B': banner = optarg; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; case 'Q': verbosity = 1; break; case 'P': flagparanoid = 0; break; case 'p': flagparanoid = 1; break; case 'O': flagkillopts = 1; break; case 'o': flagkillopts = 0; break; case 'H': flagremotehost = 0; break; case 'h': flagremotehost = 1; break; case 'R': flagremoteinfo = 0; break; case 'r': flagremoteinfo = 1; break; case 't': scan_ulong(optarg,&timeout); break; case 'T': scan_ulong(optarg,&ssltimeout); break; case 'w': scan_uint(optarg,&io_opt.timeout); break; case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); x = env_get("GID"); if (x) scan_ulong(x,&gid); break; case 'u': scan_ulong(optarg,&uid); break; case 'g': scan_ulong(optarg,&gid); break; case 'Z': netif=socket_getifidx(optarg); break; case '1': flag1 = 1; break; case '4': noipv6 = 1; break; case '6': forcev6 = 1; break; case 'l': localhost = optarg; break; case '3': flag3 = 1; break; case 'I': flagclientcert = 0; break; case 'i': flagclientcert = 1; break; case 'S': flagsslenv = 0; break; case 's': flagsslenv = 1; break; case 'E': flagtcpenv = 0; break; case 'e': flagtcpenv = 1; break; case 'n': case 'y': flagsslwait = 1; break; case 'N': case 'Y': flagsslwait = 0; break; case 'j': io_opt.just_shutdown = 1; break; case 'J': io_opt.just_shutdown = 0; break; default: usage(); } argc -= optind; argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv++; if (!hostname) usage(); if (str_equal(hostname,"")) hostname = "0"; x = *argv++; if (!x) usage(); prog = argv; if (!*argv) usage(); if (!x[scan_ulong(x,&u)]) localport = u; else { se = getservbyname(x,"tcp"); if (!se) strerr_die3x(111,FATAL,"unable to figure out port number for ",x); uint16_unpack_big((char*)&se->s_port,&localport); } if (x = env_get("VERIFYDEPTH")) { scan_ulong(x,&u); verifydepth = u; } if (x = env_get("CAFILE")) cafile = x; if (cafile && str_equal(cafile,"")) cafile = 0; if (x = env_get("CCAFILE")) ccafile = x; if (ccafile && str_equal(ccafile,"")) ccafile = 0; if (!flagclientcert) ccafile = 0; if (x = env_get("CADIR")) cadir = x; if (cadir && str_equal(cadir,"")) cadir= 0; if (x = env_get("CERTFILE")) certfile = x; if (certfile && str_equal(certfile,"")) certfile = 0; if (x = env_get("KEYFILE")) keyfile = x; if (keyfile && str_equal(keyfile,"")) keyfile = 0; if (x = env_get("DHFILE")) dhfile = x; if (dhfile && str_equal(dhfile,"")) dhfile = 0; if (x = env_get("CIPHERS")) ciphers = x; if (ciphers && str_equal(ciphers,"")) ciphers = 0; sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); if (str_equal(hostname,"0")) { byte_zero(localip,sizeof localip); } else { if (!stralloc_copys(&tmp,hostname)) strerr_die2x(111,FATAL,"out of memory"); if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); if (addresses.len < 16) strerr_die3x(111,FATAL,"no IP address for ",hostname); byte_copy(localip,16,addresses.s); if (ip6_isv4mapped(localip)) noipv6=1; } s = socket_tcp6(); if (s == -1) strerr_die2sys(111,FATAL,"unable to create socket: "); if (socket_bind6_reuse(s,localip,localport,netif) == -1) strerr_die2sys(111,FATAL,"unable to bind: "); if (socket_local6(s,localip,&localport,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get local address: "); if (socket_listen(s,backlog) == -1) strerr_die2sys(111,FATAL,"unable to listen: "); ndelay_off(s); localportstr[fmt_ulong(localportstr,localport)] = 0; if (flag1) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); buffer_puts(&b,localportstr); buffer_puts(&b,"\n"); buffer_flush(&b); } if (flag3) read_passwd(); ctx = ssl_server(); ssl_errstr(); if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context"); switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { case -1: strerr_die2x(111,FATAL,"unable to load certificate"); case -2: strerr_die2x(111,FATAL,"unable to load key"); case -3: strerr_die2x(111,FATAL,"key does not match certificate"); default: break; } if (!ssl_ca(ctx,cafile,cadir,verifydepth)) strerr_die2x(111,FATAL,"unable to load CA list"); if (!ssl_cca(ctx,ccafile)) strerr_die2x(111,FATAL,"unable to load client CA list"); if (!ssl_params(ctx,dhfile,rsalen)) strerr_die2x(111,FATAL,"unable to set cipher parameters"); if (!ssl_ciphers(ctx,ciphers)) strerr_die2x(111,FATAL,"unable to set cipher list"); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strnum2[fmt_ulong(strnum2,rsalen)] = 0; strerr_warn4("sslserver: cafile ",strnum," ",cafile,0); strerr_warn4("sslserver: ccafile ",strnum," ",ccafile,0); strerr_warn4("sslserver: cadir ",strnum," ",cadir,0); strerr_warn4("sslserver: cert ",strnum," ",certfile,0); strerr_warn4("sslserver: key ",strnum," ",keyfile,0); strerr_warn6("sslserver: param ",strnum," ",dhfile," ",strnum2,0); } close(0); open_read("/dev/null"); close(1); open_append("/dev/null"); printstatus(); for (;;) { while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); t = socket_accept6(s,remoteip,&remoteport,&netif); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); switch(fork()) { case 0: close(s); doit(t); strerr_die4sys(111,DROP,"unable to run ",*argv,": "); case -1: strerr_warn2(DROP,"unable to fork: ",&strerr_sys); --numchildren; printstatus(); } close(t); } }
int runsvdir_main(int argc UNUSED_PARAM, 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; pid_t pid; unsigned deadline; unsigned now; unsigned stampcheck; int i; int need_rescan = 1; char *opt_s_argv[3]; INIT_G(); opt_complementary = "-1"; opt_s_argv[0] = NULL; opt_s_argv[2] = NULL; getopt32(argv, "Ps:", &opt_s_argv[0]); argv += optind; bb_signals(0 | (1 << SIGTERM) | (1 << SIGHUP) /* For busybox's init, SIGTERM == reboot, * SIGUSR1 == halt * SIGUSR2 == poweroff * so we need to intercept SIGUSRn too. * Note that we do not implement actual reboot * (killall(TERM) + umount, etc), we just pause * respawing and avoid exiting (-> making kernel oops). * The user is responsible for the rest. */ | (getpid() == 1 ? ((1 << SIGUSR1) | (1 << SIGUSR2)) : 0) , record_signo); svdir = *argv++; #if ENABLE_FEATURE_RUNSVDIR_LOG /* setup log */ if (*argv) { rplog = *argv; rploglen = strlen(rplog); if (rploglen < 7) { warnx("log must have at least seven characters"); } else if (piped_pair(logpipe)) { warnx("can't create pipe for log"); } else { close_on_exec_on(logpipe.rd); close_on_exec_on(logpipe.wr); ndelay_on(logpipe.rd); ndelay_on(logpipe.wr); if (dup2(logpipe.wr, 2) == -1) { warnx("can't set filedescriptor for log"); } else { pfd[0].fd = logpipe.rd; pfd[0].events = POLLIN; stamplog = monotonic_sec(); goto run; } } rplog = NULL; warnx("log service disabled"); } run: #endif curdir = open(".", O_RDONLY|O_NDELAY); if (curdir == -1) fatal2_cannot("open current directory", ""); close_on_exec_on(curdir); stampcheck = monotonic_sec(); for (;;) { /* collect children */ for (;;) { pid = wait_any_nohang(&wstat); if (pid <= 0) break; for (i = 0; i < svnum; i++) { if (pid == sv[i].pid) { /* runsv has died */ sv[i].pid = 0; need_rescan = 1; } } } now = monotonic_sec(); if ((int)(now - stampcheck) >= 0) { /* wait at least a second */ stampcheck = now + 1; if (stat(svdir, &s) != -1) { if (need_rescan || 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; /* if the svdir changed this very second, wait until the * next second, because we won't be able to detect more * changes within this second */ while (time(NULL) == last_mtime) usleep(100000); need_rescan = do_rescan(); while (fchdir(curdir) == -1) { warn2_cannot("change directory, pausing", ""); sleep(5); } } else { warn2_cannot("change directory to ", svdir); } } } else { warn2_cannot("stat ", svdir); } } #if ENABLE_FEATURE_RUNSVDIR_LOG if (rplog) { if ((int)(now - stamplog) >= 0) { write(logpipe.wr, ".", 1); stamplog = now + 900; } } pfd[0].revents = 0; #endif deadline = (need_rescan ? 1 : 5); sig_block(SIGCHLD); #if ENABLE_FEATURE_RUNSVDIR_LOG if (rplog) poll(pfd, 1, deadline*1000); else #endif sleep(deadline); sig_unblock(SIGCHLD); #if ENABLE_FEATURE_RUNSVDIR_LOG if (pfd[0].revents & POLLIN) { char ch; while (read(logpipe.rd, &ch, 1) > 0) { if (ch < ' ') ch = ' '; for (i = 6; i < rploglen; i++) rplog[i-1] = rplog[i]; rplog[rploglen-1] = ch; } } #endif if (!bb_got_signal) continue; /* -s SCRIPT: useful if we are init. * In this case typically script never returns, * it halts/powers off/reboots the system. */ if (opt_s_argv[0]) { /* Single parameter: signal# */ opt_s_argv[1] = utoa(bb_got_signal); pid = spawn(opt_s_argv); if (pid > 0) { /* Remembering to wait for _any_ children, * not just pid */ while (wait(NULL) != pid) continue; } } if (bb_got_signal == SIGHUP) { for (i = 0; i < svnum; i++) if (sv[i].pid) kill(sv[i].pid, SIGTERM); } /* SIGHUP or SIGTERM (or SIGUSRn if we are init) */ /* Exit unless we are init */ if (getpid() != 1) return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS; /* init continues to monitor services forever */ bb_got_signal = 0; } /* for (;;) */ }
int main(int argc,char **argv) { char *hostname; // char *portname; int opt; struct servent *se; char *x; unsigned long u; int s; int t; while ((opt = getopt(argc,argv,"4dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; case 'X': flagallownorules = 1; break; case 'x': fnrules = optarg; break; case 'B': banner = optarg; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; case 'Q': verbosity = 1; break; case 'P': flagparanoid = 0; break; case 'p': flagparanoid = 1; break; case 'O': flagkillopts = 1; break; case 'o': flagkillopts = 0; break; case 'H': flagremotehost = 0; break; case 'h': flagremotehost = 1; break; // case 'R': flagremoteinfo = 0; break; case 'r': flagremoteinfo = 1; break; case 't': scan_ulong(optarg,&timeout); break; case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); x = env_get("GID"); if (x) scan_ulong(x,&gid); break; case 'u': scan_ulong(optarg,&uid); break; case 'g': scan_ulong(optarg,&gid); break; case 'I': netif=socket_getifidx(optarg); break; case '1': flag1 = 1; break; // case '4': noipv6 = 1; break; case '4': ipv4socket = 1; break; // case '6': forcev6 = 1; break; case 'l': localhost = optarg; break; default: usage(); } argc -= optind; argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv++; if (!hostname) usage(); if (str_equal(hostname,"")) hostname = "0"; x = *argv++; if (!x) usage(); if (!x[scan_ulong(x,&u)]) localport = u; else { se = getservbyname(x,"tcp"); if (!se) errint(EHARD,B("unable to figure out port number for ",x)); uint16_unpack_big((char*)&se->s_port,&localport); } if (!*argv) usage(); sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); if (str_equal(hostname,"0")) { byte_zero(localip,sizeof localip); } else { if (!stralloc_copys(&tmp,hostname)) errmem; if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) errint(EHARD,B("temporarily unable to figure out IP address for ",hostname,": ")); if (addresses.len < 16) errint(EHARD,B("no IP address for ",hostname)); byte_copy(localip,16,addresses.s); if (ip6_isv4mapped(localip)) ipv4socket = 1; } s = socket_tcp(); if (s == -1) errint(EHARD,"unable to create socket: "); if (socket_bind_reuse(s,localip,localport,netif) == -1) errint(EHARD,"unable to bind: "); if (!ipv4socket) ipv4socket = ip6_isv4mapped(localip); if (socket_local(s,localip,&localport,&netif) == -1) errint(EHARD,"unable to get local address: "); if (socket_listen(s,backlog) == -1) errint(EHARD,"unable to listen: "); ndelay_off(s); if (gid) if (prot_gid(gid) == -1) errint(EHARD,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) errint(EHARD,"unable to set uid: "); localportstr[fmt_ulong(localportstr,localport)] = 0; if (flag1) { buffer_init(&b,write,1,bspace,sizeof bspace); buffer_puts(&b,localportstr); buffer_puts(&b,"\n"); buffer_flush(&b); } close(0); close(1); printstatus(); for (;;) { while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); t = socket_accept(s,remoteip,&remoteport,&netif); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); switch(fork()) { case 0: close(s); doit(t); if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) errint(EHARD,"unable to set up descriptors: "); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); pathexec(argv); errint(EHARD,B("unable to run ",*argv,": ")); case -1: errlog(ESOFT,NOTICE,"unable to fork: "); --numchildren; printstatus(); } close(t); } }
int main(int argc, char **argv) { struct sigaction sa; if (parse_argv(argc, argv) < 0) _exit(100); snprintf(status_files[0], 1024, "%s/lock", status_dir); snprintf(status_files[1], 1024, "%s/control", status_dir); snprintf(status_files[2], 1024, "%s/ok", status_dir); snprintf(status_files[3], 1024, "%s/status", status_dir); snprintf(status_files[4], 1024, "%s/status.new", status_dir); snprintf(status_files[5], 1024, "%s/supervise.log", status_dir); snprintf(status_files[6], 1024, "%s/supervise.log.wf", status_dir); sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); if (sigaction(SIGHUP, &sa, NULL) < 0) { printf("unable to ignore SIGHUP for %s\n", service); _exit(110); } if (mkdir(status_dir, 0700) < 0 && errno != EEXIST) { printf("unable to create dir: %s\n", status_dir); _exit(110); } fdlog = open_append(status_files[5]); if (fdlog == -1) { printf("unable to open %s%s", status_dir, "/supervise.log"); _exit(111); } coe(fdlog); fdlogwf = open_append(status_files[6]); if (fdlogwf == -1) { printf("unable to open %s%s", status_dir, "/supervise.log.wf"); _exit(1); } coe(fdlogwf); if (daemon(1, 0) < 0) { printf("failed to daemonize supervise!\n"); _exit(111); } if (pipe(selfpipe) == -1) { write_log(fdlogwf, FATAL, "unable to create pipe for ", service, "\n"); _exit(111); } coe(selfpipe[0]); coe(selfpipe[1]); ndelay_on(selfpipe[0]); ndelay_on(selfpipe[1]); sig_block(sig_child); sig_catch(sig_child, trigger); sig_block(sig_alarm); sig_catch(sig_alarm, timer_handler); sig_unblock(sig_alarm); fdlock = open_append(status_files[0]); if ((fdlock == -1) || (lock_exnb(fdlock) == -1)) { write_log(fdlogwf, FATAL, "Unable to acquier ", status_dir, "/lock\n"); _exit(111); } coe(fdlock); fifo_make(status_files[1], 0600); fdcontrol = open_read(status_files[1]); if (fdcontrol == -1) { write_log(fdlogwf, FATAL, "unable to read ", status_dir, "/control\n"); _exit(1); } coe(fdcontrol); ndelay_on(fdcontrol); fdcontrolwrite = open_write(status_files[1]); if (fdcontrolwrite == -1) { write_log(fdlogwf, FATAL, "unable to write ", status_dir, "/control\n"); _exit(1); } coe(fdcontrolwrite); fifo_make(status_files[2], 0600); fdok = open_read(status_files[2]); if (fdok == -1) { write_log(fdlogwf, FATAL, "unable to read ", status_dir, "/ok\n"); _exit(1); } coe(fdok); if (!restart_sh[0]) { parse_conf(); } pidchange(); announce(); if (!flagwant || flagwantup) trystart(); doit(); announce(); _exit(0); }
int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv) { char *str_C, *str_t; char *user; struct hcc *hccp; const char *instructs; char *msg_per_host = NULL; unsigned len_per_host = len_per_host; /* gcc */ #ifndef SSLSVD struct bb_uidgid_t ugid; #endif bool tcp; uint16_t local_port; char *preset_local_hostname = NULL; char *remote_hostname = remote_hostname; /* for compiler */ char *remote_addr = remote_addr; /* for compiler */ len_and_sockaddr *lsa; len_and_sockaddr local, remote; socklen_t sa_len; int pid; int sock; int conn; unsigned backlog = 20; INIT_G(); tcp = (applet_name[0] == 't'); /* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */ opt_complementary = "-3:i--i:ph:vv:b+:c+"; #ifdef SSLSVD getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose ); #else /* "+": stop on first non-option */ getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v", &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, &backlog, &str_t, &verbose ); #endif if (option_mask32 & OPT_C) { /* -C n[:message] */ max_per_host = bb_strtou(str_C, &str_C, 10); if (str_C[0]) { if (str_C[0] != ':') bb_show_usage(); msg_per_host = str_C + 1; len_per_host = strlen(msg_per_host); } } if (max_per_host > cmax) max_per_host = cmax; if (option_mask32 & OPT_u) { if (!get_uidgid(&ugid, user, 1)) bb_error_msg_and_die("unknown user/group: %s", user); } #ifdef SSLSVD if (option_mask32 & OPT_U) ssluser = optarg; if (option_mask32 & OPT_slash) root = optarg; if (option_mask32 & OPT_Z) cert = optarg; if (option_mask32 & OPT_K) key = optarg; #endif argv += optind; if (!argv[0][0] || LONE_CHAR(argv[0], '0')) argv[0] = (char*)"0.0.0.0"; /* Per-IP flood protection is not thought-out for UDP */ if (!tcp) max_per_host = 0; bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */ #ifdef SSLSVD sslser = user; client = 0; if ((getuid() == 0) && !(option_mask32 & OPT_u)) { xfunc_exitcode = 100; bb_error_msg_and_die("-U ssluser must be set when running as root"); } if (option_mask32 & OPT_u) if (!uidgid_get(&sslugid, ssluser, 1)) { if (errno) { bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser); } bb_error_msg_and_die("unknown user/group '%s'", ssluser); } if (!cert) cert = "./cert.pem"; if (!key) key = cert; if (matrixSslOpen() < 0) fatal("cannot initialize ssl"); if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) { if (client) fatal("cannot read cert, key, or ca file"); fatal("cannot read cert or key file"); } if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0) fatal("cannot create ssl session"); #endif sig_block(SIGCHLD); signal(SIGCHLD, sig_child_handler); bb_signals(BB_FATAL_SIGS, sig_term_handler); signal(SIGPIPE, SIG_IGN); if (max_per_host) ipsvd_perhost_init(cmax); local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0); lsa = xhost2sockaddr(argv[0], local_port); argv += 2; sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); setsockopt_reuseaddr(sock); sa_len = lsa->len; /* I presume sockaddr len stays the same */ xbind(sock, &lsa->u.sa, sa_len); if (tcp) xlisten(sock, backlog); else /* udp: needed for recv_from_to to work: */ socket_want_pktinfo(sock); /* ndelay_off(sock); - it is the default I think? */ #ifndef SSLSVD if (option_mask32 & OPT_u) { /* drop permissions */ xsetgid(ugid.gid); xsetuid(ugid.uid); } #endif if (verbose) { char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa); bb_error_msg("listening on %s, starting", addr); free(addr); #ifndef SSLSVD if (option_mask32 & OPT_u) printf(", uid %u, gid %u", (unsigned)ugid.uid, (unsigned)ugid.gid); #endif } /* Main accept() loop */ again: hccp = NULL; while (cnum >= cmax) wait_for_any_sig(); /* expecting SIGCHLD */ /* Accept a connection to fd #0 */ again1: close(0); again2: sig_unblock(SIGCHLD); local.len = remote.len = sa_len; if (tcp) { conn = accept(sock, &remote.u.sa, &remote.len); } else { /* In case recv_from_to won't be able to recover local addr. * Also sets port - recv_from_to is unable to do it. */ local = *lsa; conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.u.sa, &local.u.sa, sa_len); } sig_block(SIGCHLD); if (conn < 0) { if (errno != EINTR) bb_perror_msg(tcp ? "accept" : "recv"); goto again2; } xmove_fd(tcp ? conn : sock, 0); if (max_per_host) { /* Drop connection immediately if cur_per_host > max_per_host * (minimizing load under SYN flood) */ remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa); cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp); if (cur_per_host > max_per_host) { /* ipsvd_perhost_add detected that max is exceeded * (and did not store ip in connection table) */ free(remote_addr); if (msg_per_host) { /* don't block or test for errors */ send(0, msg_per_host, len_per_host, MSG_DONTWAIT); } goto again1; } /* NB: remote_addr is not leaked, it is stored in conn table */ } if (!tcp) { /* Voodoo magic: making udp sockets each receive its own * packets is not trivial, and I still not sure * I do it 100% right. * 1) we have to do it before fork() * 2) order is important - is it right now? */ /* Open new non-connected UDP socket for further clients... */ sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0); setsockopt_reuseaddr(sock); /* Make plain write/send work for old socket by supplying default * destination address. This also restricts incoming packets * to ones coming from this remote IP. */ xconnect(0, &remote.u.sa, sa_len); /* hole? at this point we have no wildcard udp socket... * can this cause clients to get "port unreachable" icmp? * Yup, time window is very small, but it exists (is it?) */ /* ..."open new socket", continued */ xbind(sock, &lsa->u.sa, sa_len); socket_want_pktinfo(sock); /* Doesn't work: * we cannot replace fd #0 - we will lose pending packet * which is already buffered for us! And we cannot use fd #1 * instead - it will "intercept" all following packets, but child * does not expect data coming *from fd #1*! */ #if 0 /* Make it so that local addr is fixed to localp->u.sa * and we don't accidentally accept packets to other local IPs. */ /* NB: we possibly bind to the _very_ same_ address & port as the one * already bound in parent! This seems to work in Linux. * (otherwise we can move socket to fd #0 only if bind succeeds) */ close(0); set_nport(localp, htons(local_port)); xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0); setsockopt_reuseaddr(0); /* crucial */ xbind(0, &localp->u.sa, localp->len); #endif } pid = vfork(); if (pid == -1) { bb_perror_msg("vfork"); goto again; } if (pid != 0) { /* Parent */ cnum++; if (verbose) connection_status(); if (hccp) hccp->pid = pid; /* clean up changes done by vforked child */ undo_xsetenv(); goto again; } /* Child: prepare env, log, and exec prog */ /* Closing tcp listening socket */ if (tcp) close(sock); { /* vfork alert! every xmalloc in this block should be freed! */ char *local_hostname = local_hostname; /* for compiler */ char *local_addr = NULL; char *free_me0 = NULL; char *free_me1 = NULL; char *free_me2 = NULL; if (verbose || !(option_mask32 & OPT_E)) { if (!max_per_host) /* remote_addr is not yet known */ free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa); if (option_mask32 & OPT_h) { free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa); if (!remote_hostname) { bb_error_msg("cannot look up hostname for %s", remote_addr); remote_hostname = remote_addr; } } /* Find out local IP peer connected to. * Errors ignored (I'm not paranoid enough to imagine kernel * which doesn't know local IP). */ if (tcp) getsockname(0, &local.u.sa, &local.len); /* else: for UDP it is done earlier by parent */ local_addr = xmalloc_sockaddr2dotted(&local.u.sa); if (option_mask32 & OPT_h) { local_hostname = preset_local_hostname; if (!local_hostname) { free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa); if (!local_hostname) bb_error_msg_and_die("cannot look up hostname for %s", local_addr); } /* else: local_hostname is not NULL, but is NOT malloced! */ } } if (verbose) { pid = getpid(); if (max_per_host) { bb_error_msg("concurrency %s %u/%u", remote_addr, cur_per_host, max_per_host); } bb_error_msg((option_mask32 & OPT_h) ? "start %u %s-%s (%s-%s)" : "start %u %s-%s", pid, local_addr, remote_addr, local_hostname, remote_hostname); } if (!(option_mask32 & OPT_E)) { /* setup ucspi env */ const char *proto = tcp ? "TCP" : "UDP"; /* Extract "original" destination addr:port * from Linux firewall. Useful when you redirect * an outbond connection to local handler, and it needs * to know where it originally tried to connect */ if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) { char *addr = xmalloc_sockaddr2dotted(&local.u.sa); xsetenv_plain("TCPORIGDSTADDR", addr); free(addr); } xsetenv_plain("PROTO", proto); xsetenv_proto(proto, "LOCALADDR", local_addr); xsetenv_proto(proto, "REMOTEADDR", remote_addr); if (option_mask32 & OPT_h) { xsetenv_proto(proto, "LOCALHOST", local_hostname); xsetenv_proto(proto, "REMOTEHOST", remote_hostname); } //compat? xsetenv_proto(proto, "REMOTEINFO", ""); /* additional */ if (cur_per_host > 0) /* can not be true for udp */ xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host)); } free(local_addr); free(free_me0); free(free_me1); free(free_me2); } xdup2(0, 1); signal(SIGTERM, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGCHLD, SIG_DFL); sig_unblock(SIGCHLD); #ifdef SSLSVD strcpy(id, utoa(pid)); ssl_io(0, argv); #else BB_EXECVP(argv[0], argv); #endif bb_perror_msg_and_die("exec '%s'", argv[0]); }
void sig_alarmblock(void) { sig_block(SIGALRM); }
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; } } }
int main(int argc,char **argv) { char *hostname, *x; int c, s, t; unsigned int u; unsigned int cpid = 0; opterr = 0; while ((c = getopt(argc, argv, "dDoOC:k:c:")) != -1) switch (c) { case 'c': limit = atoi(optarg); if (limit == 0) usage(); break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'O': flagkillopts = 1; break; case 'o': flagkillopts = 0; break; case 'C': cacheprogram = 1; break; case 'k': autokill = atoi(optarg); if (autokill == 0) usage(); break; default: abort(); } argc -= optind; argv += optind; hostname = *argv++; if (!hostname) usage(); x = *argv++; if (!x) usage(); u = 0; u = atoi(x); if (u != 0) localport = u; else usage(); if (!*argv) usage(); sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_catch(sig_int,sigint); sig_ignore(sig_pipe); inet_aton(hostname, (struct in_addr *) &localip); if (autokill != 0) pt = ptable_init(limit); s = socket_tcp(); if (s == -1) die(111, "unable to create socket"); if (socket_bind4_reuse(s,localip,localport) == -1) die(111, "unable to bind"); if (socket_local4(s,localip,&localport) == -1) die(111, "unable to get local address"); if (socket_listen(s,20) == -1) die(111, "unable to listen"); ndelay_off(s); fprintf(stderr, "bind: %s:%d\n", hostname, localport); close(0); close(1); printstatus(); if (cacheprogram) { FILE *fp1; int fp2; char path[1024]; ssize_t n; fp1 = popen(*argv, "r"); if (fp1 == NULL) { fprintf(stderr, "Failed to run command\n"); exit(1); } fp2 = open("/var/tmp/tcpd.cache", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fp2 == -1) { fprintf(stderr, "Can't open cache file\n"); exit(1); } while ((n = fgets(path, sizeof(path)-1, fp1)) != NULL) { if (write(fp2, path, n) == n) { fprintf(stderr, "Error occured while creating cache\n"); exit(1); } } /* close */ pclose(fp1); close(fp2); // read cache file into memory FILE *f = fopen("/var/tmp/tcpd.cache", "rb"); fseek(f, 0, SEEK_END); cachesize = ftell(f); fseek(f, 0, SEEK_SET); //same as rewind(f); cache = malloc(cachesize + 1); n = fread(cache, cachesize, 1, f); fclose(f); cache[cachesize] = 0; } for (;;) { while (numchildren >= limit) { if (autokill != 0) ptable_autokill(pt, limit, autokill); sig_pause(); } sig_unblock(sig_child); t = socket_accept4(s,remoteip,&remoteport); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); fprintf(stderr, "inbound connection from %d.%d.%d.%d:%d\n", (unsigned char) remoteip[0], (unsigned char) remoteip[1], (unsigned char) remoteip[2], (unsigned char) remoteip[3], remoteport); if (autokill != 0) ptable_autokill(pt,limit,autokill); cpid = fork(); switch(cpid) { case 0: close(s); if(flagkillopts) socket_ipoptionskill(t); if(!flagdelay) socket_tcpnodelay(t); if((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) die(111,"unable to setup descriptors"); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_int); sig_uncatch(sig_pipe); if (cacheprogram) { printf("%s", cache); close(t); exit(0); } else { if(execve(*argv,argv,NULL) == 0) { close(t); exit(0); } else { die(111, "unable to run argv"); } } break; case -1: // unable to fork eprint(P_WARN,"unable to fork"); --numchildren; printstatus(); break; default: fprintf(stderr, "fork: child pid %d\n", cpid); if (autokill != 0) ptable_set(pt, limit, cpid, time(NULL)); break; } close(t); } }
int main(int argc, char **argv) { int opt; char *user =0; char *host; unsigned long port; int pid; int s; int conn; int delim; progname =*argv; phccmax =0; #ifdef SSLSVD while ((opt =getopt(argc, (const char **)argv, "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) { #else while ((opt =getopt(argc, (const char **)argv, "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) { #endif switch(opt) { case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break; case 'C': delim =scan_ulong(optarg, &phccmax); if (phccmax < 1) usage(); if (optarg[delim] == ':') { if (ipsvd_fmt_msg(&msg, optarg +delim +1) == -1) die_nomem(); if (! stralloc_0(&msg)) die_nomem(); phccmsg =msg.s; } break; case 'i': if (instructs) usage(); instructs =optarg; break; case 'x': if (instructs) usage(); instructs =optarg; iscdb =1; break; case 'u': user =(char*)optarg; break; case 'l': if (! stralloc_copys(&local_hostname, optarg)) die_nomem(); if (! stralloc_0(&local_hostname)) die_nomem(); break; case 'E': ucspi =0; break; case 'b': scan_ulong(optarg, &backlog); break; case 'h': lookuphost =1; break; case 'p': lookuphost =1; paranoid =1; break; case 't': scan_ulong(optarg, &timeout); break; case 'v': ++verbose; break; #ifdef SSLSVD case 'U': ssluser =(char*)optarg; break; case '/': root =(char*)optarg; break; case 'Z': cert =(char*)optarg; break; case 'K': key =(char*)optarg; break; #endif case 'V': strerr_warn1(VERSION, 0); case '?': usage(); } } argv +=optind; if (! argv || ! *argv) usage(); host =*argv++; if (! argv || ! *argv) usage(); local_port =*argv++; if (! argv || ! *argv) usage(); prog =(const char **)argv; if (phccmax > cmax) phccmax =cmax; if (user) if (! uidgids_get(&ugid, user)) { if (errno) strerr_die4sys(111, FATAL, "unable to get user/group: ", user, ": "); strerr_die3x(100, FATAL, "unknown user/group: ", user); } #ifdef SSLSVD svuser =user; client =0; if ((getuid() == 0) && (! ssluser)) strerr_die2x(100, FATAL, "-U ssluser must be set when running as root"); if (ssluser) if (! uidgids_get(&sslugid, ssluser)) { if (errno) strerr_die4sys(111, FATAL, "unable to get user/group: ", ssluser, ": "); strerr_die3x(100, FATAL, "unknown user/group: ", ssluser); } if (! cert) cert ="./cert.pem"; if (! key) key =cert; if (matrixSslOpen() < 0) fatal("unable to initialize ssl"); if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) { if (client) fatal("unable to read cert, key, or ca file"); fatal("unable to read cert or key file"); } if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0) strerr_die2x(111, FATAL, "unable to create ssl session"); #endif dns_random_init(seed); sig_block(sig_child); sig_catch(sig_child, sig_child_handler); sig_catch(sig_term, sig_term_handler); sig_ignore(sig_pipe); if (phccmax) if (ipsvd_phcc_init(cmax) == -1) die_nomem(); if (str_equal(host, "")) host ="0.0.0.0"; if (str_equal(host, "0")) host ="0.0.0.0"; if (! ipsvd_scan_port(local_port, "tcp", &port)) strerr_die3x(100, FATAL, "unknown port number or name: ", local_port); if (! stralloc_copys(&sa, host)) die_nomem(); if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4)) if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1) fatal2("unable to look up ip address", host); if (ips.len < 4) strerr_die3x(100, FATAL, "unable to look up ip address: ", host); ips.len =4; if (! stralloc_0(&ips)) die_nomem(); local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0; if (! lookuphost) { if (! stralloc_copys(&remote_hostname, "")) die_nomem(); if (! stralloc_0(&remote_hostname)) die_nomem(); } if ((s =socket_tcp()) == -1) fatal("unable to create socket"); if (socket_bind4_reuse(s, ips.s, port) == -1) fatal("unable to bind socket"); if (listen(s, backlog) == -1) fatal("unable to listen"); ndelay_off(s); #ifdef SSLSVD #else if (user) { /* drop permissions */ if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups"); if (setgid(*ugid.gid) == -1) fatal("unable to set gid"); if (prot_uid(ugid.uid) == -1) fatal("unable to set uid"); } #endif close(0); if (verbose) { out(INFO); out("listening on "); outfix(local_ip); out(":"); outfix(local_port); #ifdef SSLSVD #else if (user) { bufnum[fmt_ulong(bufnum, (unsigned long)ugid.uid)] =0; out(", uid "); out(bufnum); bufnum[fmt_ulong(bufnum, (unsigned long)ugid.gid)] =0; out(", gid "); out(bufnum); } #endif flush(", starting.\n"); } for (;;) { while (cnum >= cmax) sig_pause(); socka_size =sizeof(socka); sig_unblock(sig_child); conn =accept(s, (struct sockaddr *)&socka, &socka_size); sig_block(sig_child); if (conn == -1) { if (errno != error_intr) warn("unable to accept connection"); continue; } cnum++; if (verbose) connection_status(); if (phccmax) phcc =ipsvd_phcc_add((char*)&socka.sin_addr); if ((pid =fork()) == -1) { warn2("drop connection", "unable to fork"); close(conn); continue; } if (pid == 0) { /* child */ close(s); #ifdef SSLSVD if (*progname) *progname ='\\'; #endif connection_accept(conn); } if (phccmax) ipsvd_phcc_setpid(pid); close(conn); } _exit(0); }
void sig_childblock() { sig_block(SIGCHLD); }
int main(int argc,char * const *argv) { const char *hostname; int opt; char *x; unsigned long u; int s; int t; int flagv4 = 1, flagv6 = 1, rc; struct addrinfo *localai = NULL, hints = {0}, *ai; while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:T:u:g:l:b:B:c:pPoO3IiEeSsw:nN46")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; case 'X': flagallownorules = 1; break; case 'x': fnrules = optarg; break; case 'B': banner = optarg; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; case 'Q': verbosity = 1; break; case 'P': flagparanoid = 0; break; case 'p': flagparanoid = 1; break; case 'O': flagkillopts = 1; break; case 'o': flagkillopts = 0; break; case 'H': flagremotehost = 0; break; case 'h': flagremotehost = 1; break; case 'R': flagremoteinfo = 0; break; case 'r': flagremoteinfo = 1; break; case 't': scan_ulong(optarg,&timeout); break; case 'T': scan_ulong(optarg,&ssltimeout); break; case 'w': scan_uint(optarg,&progtimeout); break; case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); x = env_get("GID"); if (x) scan_ulong(x,&gid); break; case 'u': scan_ulong(optarg,&uid); break; case 'g': scan_ulong(optarg,&gid); break; case '1': flag1 = 1; break; case 'l': localhost = optarg; break; case '3': flag3 = 1; break; case 'I': flagclientcert = 0; break; case 'i': flagclientcert = 1; break; case 'S': flagsslenv = 0; break; case 's': flagsslenv = 1; break; case 'E': flagtcpenv = 0; break; case 'e': flagtcpenv = 1; break; case 'n': flagsslwait = 1; break; case 'N': flagsslwait = 0; break; case '4': flagv6 = 0; break; case '6': flagv4 = 0; break; default: usage(); } if (flagv4 == flagv6) { flagv4 = flagv6 = 1; } argc -= optind; argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv++; if (!hostname) usage(); if (str_equal(hostname,"")) hostname = NULL; if (str_equal(hostname,"0")) hostname = NULL; x = *argv++; if (!x) usage(); prog = argv; if (!*argv) usage(); hints.ai_family = flagv4 == flagv6 ? AF_UNSPEC : flagv4 ? AF_INET : AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if ((rc = getaddrinfo(hostname, x, &hints, &localai))) { strerr_die(111,FATAL "unable to figure out address for ", hostname ? hostname : "0", " ",x,": ",gai_strerror(rc),0); } if (!localai) { strerr_die2x(111,FATAL,"address not found"); } if (x = env_get("VERIFYDEPTH")) { scan_ulong(x,&u); verifydepth = u; } if (x = env_get("CAFILE")) cafile = x; if (cafile && str_equal(cafile,"")) cafile = 0; if (x = env_get("CCAFILE")) ccafile = x; if (ccafile && str_equal(ccafile,"")) ccafile = 0; if (!flagclientcert) ccafile = 0; if (x = env_get("CADIR")) cadir = x; if (cadir && str_equal(cadir,"")) cadir= 0; if (x = env_get("CERTCHAINFILE")) certchainfile = x; if (certchainfile && str_equal(certchainfile,"")) certchainfile = 0; if (x = env_get("CERTFILE")) certfile = x; if (certfile && str_equal(certfile,"")) certfile = 0; if (x = env_get("KEYFILE")) keyfile = x; if (keyfile && str_equal(keyfile,"")) keyfile = 0; if (x = env_get("DHFILE")) dhfile = x; if (dhfile && str_equal(dhfile,"")) dhfile = 0; if (x = env_get("CIPHERS")) ciphers = x; if (ciphers && str_equal(ciphers,"")) ciphers = 0; sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); for (ai = localai; ai; ai = ai->ai_next) { s = socket_tcp(ai->ai_family, ai->ai_protocol); if (s == -1) strerr_die2sys(111,FATAL,"unable to create socket: "); if (socket_bind_reuse(s,ai) == -1) strerr_die2sys(111,FATAL,"unable to bind: "); if (socket_local(s,&localaddr,&localport) == -1) strerr_die2sys(111,FATAL,"unable to get local address: "); if (socket_listen(s,backlog) == -1) strerr_die2sys(111,FATAL,"unable to listen: "); break; } freeaddrinfo(localai); localai = NULL; ndelay_off(s); localportstr[fmt_ulong(localportstr,localport)] = 0; if (flag1) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); buffer_puts(&b,localportstr); buffer_puts(&b,"\n"); buffer_flush(&b); } if (flag3) read_passwd(); ctx = ssl_server(); ssl_errstr(); if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context"); if (certchainfile) { switch (ssl_chainfile(ctx,certchainfile,keyfile,passwd_cb)) { case -1: strerr_die2x(111,FATAL,"unable to load certificate chain file"); case -2: strerr_die2x(111,FATAL,"unable to load key"); case -3: strerr_die2x(111,FATAL,"key does not match certificate"); default: break; } } else { switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { case -1: strerr_die2x(111,FATAL,"unable to load certificate"); case -2: strerr_die2x(111,FATAL,"unable to load key"); case -3: strerr_die2x(111,FATAL,"key does not match certificate"); default: break; } } if (!ssl_ca(ctx,cafile,cadir,verifydepth)) strerr_die2x(111,FATAL,"unable to load CA list"); if (!ssl_cca(ctx,ccafile)) strerr_die2x(111,FATAL,"unable to load client CA list"); if (!ssl_params(ctx,dhfile,rsalen)) strerr_die2x(111,FATAL,"unable to set DH/RSA parameters"); if (!ssl_ciphers(ctx,ciphers)) strerr_die2x(111,FATAL,"unable to set cipher list"); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strnum2[fmt_ulong(strnum2,rsalen)] = 0; strerr_warn4("sslserver: cafile ",strnum," ",cafile,0); strerr_warn4("sslserver: ccafile ",strnum," ",ccafile,0); strerr_warn4("sslserver: cadir ",strnum," ",cadir,0); strerr_warn4("sslserver: chainfile ",strnum," ",certchainfile,0); strerr_warn4("sslserver: cert ",strnum," ",certfile,0); strerr_warn4("sslserver: key ",strnum," ",keyfile,0); strerr_warn6("sslserver: param ",strnum," ",dhfile," ",strnum2,0); } close(0); open_read("/dev/null"); close(1); open_append("/dev/null"); printstatus(); for (;;) { while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); t = socket_accept(s,&remoteaddr,&remoteport); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); switch(fork()) { case 0: close(s); doit(t); strerr_die4sys(111,DROP,"unable to run ",*argv,": "); case -1: strerr_warn2(DROP,"unable to fork: ",&strerr_sys); --numchildren; printstatus(); } close(t); } }
int runsv_main(int argc UNUSED_PARAM, char **argv) { struct stat s; int fd; int r; char buf[256]; INIT_G(); dir = single_argv(argv); xpiped_pair(selfpipe); close_on_exec_on(selfpipe.rd); close_on_exec_on(selfpipe.wr); ndelay_on(selfpipe.rd); ndelay_on(selfpipe.wr); sig_block(SIGCHLD); bb_signals_recursive_norestart(1 << SIGCHLD, s_child); sig_block(SIGTERM); bb_signals_recursive_norestart(1 << SIGTERM, s_term); xchdir(dir); /* bss: svd[0].pid = 0; */ if (S_DOWN) svd[0].state = S_DOWN; /* otherwise already 0 (bss) */ if (C_NOOP) svd[0].ctrl = C_NOOP; if (W_UP) svd[0].sd_want = W_UP; /* bss: svd[0].islog = 0; */ /* bss: svd[1].pid = 0; */ gettimeofday_ns(&svd[0].start); if (stat("down", &s) != -1) svd[0].sd_want = W_DOWN; if (stat("log", &s) == -1) { if (errno != ENOENT) warn_cannot("stat ./log"); } else { if (!S_ISDIR(s.st_mode)) { errno = 0; warn_cannot("stat log/down: log is not a directory"); } else { haslog = 1; svd[1].state = S_DOWN; svd[1].ctrl = C_NOOP; svd[1].sd_want = W_UP; svd[1].islog = 1; gettimeofday_ns(&svd[1].start); if (stat("log/down", &s) != -1) svd[1].sd_want = W_DOWN; xpiped_pair(logpipe); close_on_exec_on(logpipe.rd); close_on_exec_on(logpipe.wr); } } if (mkdir("supervise", 0700) == -1) { r = readlink("supervise", buf, sizeof(buf)); if (r != -1) { if (r == sizeof(buf)) fatal2x_cannot("readlink ./supervise", ": name too long"); buf[r] = 0; mkdir(buf, 0700); } else { if ((errno != ENOENT) && (errno != EINVAL)) fatal_cannot("readlink ./supervise"); } } svd[0].fdlock = xopen3("log/supervise/lock"+4, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); if (flock(svd[0].fdlock, LOCK_EX | LOCK_NB) == -1) fatal_cannot("lock supervise/lock"); close_on_exec_on(svd[0].fdlock); if (haslog) { if (mkdir("log/supervise", 0700) == -1) { r = readlink("log/supervise", buf, 256); if (r != -1) { if (r == 256) fatal2x_cannot("readlink ./log/supervise", ": name too long"); buf[r] = 0; fd = xopen(".", O_RDONLY|O_NDELAY); xchdir("./log"); mkdir(buf, 0700); if (fchdir(fd) == -1) fatal_cannot("change back to service directory"); close(fd); } else { if ((errno != ENOENT) && (errno != EINVAL)) fatal_cannot("readlink ./log/supervise"); } } svd[1].fdlock = xopen3("log/supervise/lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); if (flock(svd[1].fdlock, LOCK_EX) == -1) fatal_cannot("lock log/supervise/lock"); close_on_exec_on(svd[1].fdlock); } mkfifo("log/supervise/control"+4, 0600); svd[0].fdcontrol = xopen("log/supervise/control"+4, O_RDONLY|O_NDELAY); close_on_exec_on(svd[0].fdcontrol); svd[0].fdcontrolwrite = xopen("log/supervise/control"+4, O_WRONLY|O_NDELAY); close_on_exec_on(svd[0].fdcontrolwrite); update_status(&svd[0]); if (haslog) { mkfifo("log/supervise/control", 0600); svd[1].fdcontrol = xopen("log/supervise/control", O_RDONLY|O_NDELAY); close_on_exec_on(svd[1].fdcontrol); svd[1].fdcontrolwrite = xopen("log/supervise/control", O_WRONLY|O_NDELAY); close_on_exec_on(svd[1].fdcontrolwrite); update_status(&svd[1]); } mkfifo("log/supervise/ok"+4, 0600); fd = xopen("log/supervise/ok"+4, O_RDONLY|O_NDELAY); close_on_exec_on(fd); if (haslog) { mkfifo("log/supervise/ok", 0600); fd = xopen("log/supervise/ok", O_RDONLY|O_NDELAY); close_on_exec_on(fd); } for (;;) { struct pollfd x[3]; unsigned deadline; char ch; if (haslog) if (!svd[1].pid && svd[1].sd_want == W_UP) startservice(&svd[1]); if (!svd[0].pid) if (svd[0].sd_want == W_UP || svd[0].state == S_FINISH) startservice(&svd[0]); x[0].fd = selfpipe.rd; x[0].events = POLLIN; x[1].fd = svd[0].fdcontrol; x[1].events = POLLIN; /* x[2] is used only if haslog == 1 */ x[2].fd = svd[1].fdcontrol; x[2].events = POLLIN; sig_unblock(SIGTERM); sig_unblock(SIGCHLD); poll(x, 2 + haslog, 3600*1000); sig_block(SIGTERM); sig_block(SIGCHLD); while (read(selfpipe.rd, &ch, 1) == 1) continue; for (;;) { pid_t child; int wstat; child = wait_any_nohang(&wstat); if (!child) break; if ((child == -1) && (errno != EINTR)) break; if (child == svd[0].pid) { svd[0].wstat = wstat; svd[0].pid = 0; pidchanged = 1; svd[0].ctrl &= ~C_TERM; if (svd[0].state != S_FINISH) { fd = open("finish", O_RDONLY|O_NDELAY); if (fd != -1) { close(fd); svd[0].state = S_FINISH; update_status(&svd[0]); continue; } } svd[0].state = S_DOWN; deadline = svd[0].start.tv_sec + 1; gettimeofday_ns(&svd[0].start); update_status(&svd[0]); if (LESS(svd[0].start.tv_sec, deadline)) sleep(1); } if (haslog) { if (child == svd[1].pid) { svd[0].wstat = wstat; svd[1].pid = 0; pidchanged = 1; svd[1].state = S_DOWN; svd[1].ctrl &= ~C_TERM; deadline = svd[1].start.tv_sec + 1; gettimeofday_ns(&svd[1].start); update_status(&svd[1]); if (LESS(svd[1].start.tv_sec, deadline)) sleep(1); } } } /* for (;;) */ if (read(svd[0].fdcontrol, &ch, 1) == 1) ctrl(&svd[0], ch); if (haslog) if (read(svd[1].fdcontrol, &ch, 1) == 1) ctrl(&svd[1], ch); if (sigterm) { ctrl(&svd[0], 'x'); sigterm = 0; } if (svd[0].sd_want == W_EXIT && svd[0].state == S_DOWN) { if (svd[1].pid == 0) _exit(EXIT_SUCCESS); if (svd[1].sd_want != W_EXIT) { svd[1].sd_want = W_EXIT; /* stopservice(&svd[1]); */ update_status(&svd[1]); close(logpipe.wr); close(logpipe.rd); } } } /* for (;;) */ /* not reached */ return 0; }
/* execute another program, possibly searching for it first * * if the 'exec' argument is set it will never return * ----------------------------------------------------------------------- */ int exec_program(char *path, char **argv, int exec, union node *redir) { int ret = 0; sigset_t nset, oset; /* if we're gonna execve() a program and 'exec' isn't set or we aren't in the root shell environment we have to fork() so we can return */ if(!exec || sh->parent) { pid_t pid; struct fdstack io; unsigned int n; fdstack_push(&io); /* buffered fds which have not a real effective file descriptor, like here-docs which are read from strallocs and command expansions, which write to strallocs can't be shared across different process spaces, so we have to establish pipes */ if((n = fdstack_npipes(FD_HERE|FD_SUBST))) fdstack_pipe(n, fdstack_alloc(n)); /* block child and interrupt signal, so we won't terminate ourselves when the child does */ /* sigemptyset(&nset); sigaddset(&nset, SIGINT); #ifdef SIGCHLD sigaddset(&nset, SIGCHLD); #endif sigemptyset(&oset); sigprocmask(SIG_BLOCK, &nset, &oset); */ sig_block(); /* in the parent wait for the child to finish and then return or exit, according to the 'exec' argument */ if((pid = fork())) { int status = 1; /* this will close child ends of the pipes and read data from the parent end :) */ fdstack_pop(&io); fdstack_data(); job_wait(NULL, pid, &status, 0); job_status(pid, status); ret = WEXITSTATUS(status); #ifndef __MINGW32__ sigprocmask(SIG_SETMASK, &oset, NULL); #endif /* exit if 'exec' is set, otherwise return */ if(exec) sh_exit(ret); return ret; } /* ...in the child we always exit */ sh_forked(); } fdtable_exec(); fdstack_flatten(); /* when there is a path then we gotta execute a command, otherwise we exit/return immediately */ if(path) { /* export environment */ char **envp; unsigned long envn = var_count(V_EXPORT) + 1; envp = var_export(alloca(envn * sizeof(char *))); /* try to execute the program */ execve(path, argv, envp); /* execve() returned so it failed, we're gonna map the error code to the appropriate POSIX errors */ ret = exec_error(); /* yield an error message */ sh_error(path); } /* we never return at this point! */ exit(ret); }
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); }
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 }