Exemplo n.º 1
0
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();
 }
}
Exemplo n.º 2
0
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();
  }
}
Exemplo n.º 3
0
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();
  }
}
Exemplo n.º 4
0
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;
                }
}
Exemplo n.º 5
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();
}
Exemplo n.º 6
0
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 ;
      }
    }
  }
}
Exemplo n.º 7
0
Arquivo: runit.c Projeto: Gottox/runit
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);
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
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);
}
Exemplo n.º 10
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,": ");
}
Exemplo n.º 11
0
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,": ");
}
Exemplo n.º 12
0
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] ;
      }
    }
  }
}
Exemplo n.º 13
0
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;
      }
  }
}
Exemplo n.º 14
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
}