예제 #1
0
int
dns_resolve (const char *q, const char qtype[2])
{
    int r = 0;
    char servers[64];
    iopause_fd x[1];

    struct taia stamp;
    struct taia deadline;

    if (dns_resolvconfip (servers) == -1)
        return -1;

    memset (&dns_resolve_tx, 0, sizeof (dns_resolve_tx));
    r = dns_transmit_start (&dns_resolve_tx, servers, 1, q, qtype, "\0\0\0\0");
    if (r == -1)
        return -1;

    for (;;)
    {
        taia_now (&stamp);
        taia_uint (&deadline, 120);
        taia_add (&deadline, &deadline, &stamp);

        dns_transmit_io (&dns_resolve_tx, x, &deadline);
        iopause (x, 1, &deadline, &stamp);

        r = dns_transmit_get (&dns_resolve_tx, x, &stamp);
        if (r == -1)
            return -1;
        if (r == 1)
            return 0;
    }
}
int timeoutconn6(int s,const char ip[16],uint16 port,unsigned int scope_id,unsigned int timeout)
{
  struct taia now;
  struct taia deadline;
  iopause_fd x;

  if (socket_connect6(s,ip,port,scope_id) == -1) {
    if ((errno != EWOULDBLOCK) && (errno != EINPROGRESS)) return -1;
    x.fd = s;
    x.events = IOPAUSE_WRITE;
    taia_now(&now);
    taia_uint(&deadline,timeout);
    taia_add(&deadline,&now,&deadline);
    for (;;) {
      taia_now(&now);
      iopause(&x,1,&deadline,&now);
      if (x.revents) break;
      if (taia_less(&deadline,&now)) {
	errno = ETIMEDOUT; /* note that connect attempt is continuing */
	return -1;
      }
    }
    if (!socket_connected(s)) return -1;
  }

  if (ndelay_off(s) == -1) return -1;
  return 0;
}
예제 #3
0
int timeoutconn(int s,char ip[4],uint16 port,unsigned int timeout)
{
  struct taia now;
  struct taia deadline;
  iopause_fd x;

  if (socket_connect4(s,ip,port) == -1) {
    if ((errno != error_wouldblock) && (errno != error_inprogress)) return -1;
    x.fd = s;
    x.events = IOPAUSE_WRITE;
    taia_now(&now);
    taia_uint(&deadline,timeout);
    taia_add(&deadline,&now,&deadline);
    for (;;) {
      taia_now(&now);
      iopause(&x,1,&deadline,&now);
      if (x.revents) break;
      if (taia_less(&deadline,&now)) {
	    errno = error_timeout; /* note that connect attempt is continuing */
	    return -1;
      }
    }
    if (!socket_connected(s)) return -1;
  }

  if (ndelay_off(s) == -1) return -1;
  return 0;
}
예제 #4
0
static int myread(int fd,char *buf,int len)
{
  iopause_fd x;

  x.fd = fd;
  x.events = IOPAUSE_READ;
  for (;;) {
    taia_now(&now);
    iopause(&x,1,&deadline,&now);
    if (x.revents) break;
    if (taia_less(&deadline,&now)) {
      errno = error_timeout;
      return -1;
    }
  }
  return read(fd,buf,len);
}
예제 #5
0
int ssl_timeoutaccept(SSL *ssl,unsigned int timeout)
{
  struct taia now;
  struct taia deadline;
  iopause_fd x;
  int r;
  int rfd;
  int wfd;

  taia_now(&now);
  taia_uint(&deadline,timeout);
  taia_add(&deadline,&now,&deadline);

  rfd = SSL_get_fd(ssl); /* XXX */
  wfd = SSL_get_fd(ssl); /* XXX */

  SSL_set_accept_state(ssl);

  for (;;) {
    r = SSL_accept(ssl);
    if (r == 1) return 0;
    ssl_errno = SSL_get_error(ssl,r);
    errno = error_proto;
    if ((ssl_errno != SSL_ERROR_WANT_READ) && (ssl_errno != SSL_ERROR_WANT_WRITE))
      return -1;
    if (ssl_errno == SSL_ERROR_WANT_READ) {
      x.events = IOPAUSE_READ;
      x.fd = rfd;
      if (x.fd == -1) return -1;
    }
    else {
      x.events = IOPAUSE_WRITE;
      x.fd = wfd;
      if (x.fd == -1) return -1;
    }
    for (;;) {
      taia_now(&now);
      iopause(&x,1,&deadline,&now);
      if (x.revents) break;
      if (taia_less(&deadline,&now))
	return -1;
    }
  }
}
예제 #6
0
int dns_resolve(const char *q,const char qtype[2])
{
  struct taia stamp;
  struct taia deadline;
  char servers[256];
  iopause_fd x[1];
  int r;

  if (dns_resolvconfip(servers) == -1) return -1;
  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;

  for (;;) {
    taia_now(&stamp);
    taia_uint(&deadline,120);
    taia_add(&deadline,&deadline,&stamp);
    dns_transmit_io(&dns_resolve_tx,x,&deadline);
    iopause(x,1,&deadline,&stamp);
    r = dns_transmit_get(&dns_resolve_tx,x,&stamp);
    if (r == -1) return -1;
    if (r == 1) return 0;
  }
}
예제 #7
0
파일: dnsq.c 프로젝트: axlecrusher/djbdns
int resolve(char *q,char qtype[2],char servers[256])
{
  struct taia stamp;
  struct taia deadline;
  iopause_fd x[1];
  int r;

  if (dns_transmit_start(&tx,servers,0,q,qtype,V6any) == -1) return -1;

  for (;;) {
    taia_now(&stamp);
    taia_uint(&deadline,120);
    taia_add(&deadline,&deadline,&stamp);
    dns_transmit_io(&tx,x,&deadline);
    iopause(x,1,&deadline,&stamp);
    r = dns_transmit_get(&tx,x,&stamp);
    if (r == -1) return -1;
    if (r == 1) break;
  }

  return 0;
}
예제 #8
0
int timeoutread(int t,int fd,char *buf,int len)
{
  struct taia now;
  struct taia deadline;
  iopause_fd x;

  taia_now(&now);
  taia_uint(&deadline,t);
  taia_add(&deadline,&now,&deadline);

  x.fd = fd;
  x.events = IOPAUSE_READ;
  for (;;) {
    taia_now(&now);
    iopause(&x,1,&deadline,&now);
    if (x.revents) break;
    if (taia_less(&deadline,&now)) {
      errno = ETIMEDOUT;
      return -1;
    }
  }
  return read(fd,buf,len);
}
예제 #9
0
int timeoutwrite(int t,int fd,const char *buf,int len)
{
  struct taia now;
  struct taia deadline;
  iopause_fd x;

  taia_now(&now);
  taia_uint(&deadline,t);
  taia_add(&deadline,&now,&deadline);

  x.fd = fd;
  x.events = IOPAUSE_WRITE;
  for (;;) {
    taia_now(&now);
    iopause(&x,1,&deadline,&now);
    if (x.revents) break;
    if (taia_less(&deadline,&now)) {
      errno = error_timeout;
      return -1;
    }
  }
  return write(fd,buf,len);
}
예제 #10
0
int resolve(char *q,char qtype[2],char ip[16])
{
  struct taia start;
  struct taia stamp;
  struct taia deadline;
  char servers[256];
  iopause_fd x[1];
  int r;

  taia_now(&start);

  byte_zero(servers,256);
  byte_copy(servers,16,ip);

  if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1;

  for (;;) {
    taia_now(&stamp);
    taia_uint(&deadline,120);
    taia_add(&deadline,&deadline,&stamp);
    dns_transmit_io(&tx,x,&deadline);
    iopause(x,1,&deadline,&stamp);
    r = dns_transmit_get(&tx,x,&stamp);
    if (r == -1) return -1;
    if (r == 1) break;
  }

  taia_now(&stamp);
  taia_sub(&stamp,&stamp,&start);
  taia_uint(&deadline,1);
  if (taia_less(&deadline,&stamp)) {
    buffer_put(buffer_1,querystr.s,querystr.len);
    buffer_puts(buffer_1,"ALERT:took more than 1 second\n");
  }

  return 0;
}
int timeoutaccept6(int s,char ip[16],uint16 *port,unsigned int timeout,uint32 *scope_id)
{
  struct taia now;
  struct taia deadline;
  iopause_fd x;

  x.fd = s;
  x.events = IOPAUSE_READ;
  taia_now(&now);
  taia_uint(&deadline,timeout);
  taia_add(&deadline,&now,&deadline);
  for (;;) {
    taia_now(&now);
    iopause(&x,1,&deadline,&now);
    if (x.revents) break;
    if (taia_less(&deadline,&now)) {
      errno = ETIMEDOUT; /* note that connect attempt is continuing */
      return -1;
    }
  }
  if (!socket_connected(s)) return -1;
  if (ndelay_off(s) == -1) return -1;
  return socket_accept6(s,ip,port,scope_id);
}
예제 #12
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);
}
예제 #13
0
int
main (int argc, char *argv[])
{
    time_t t = 0;
    char *x = NULL;
    struct sigaction sa;
    iopause_fd *iop = NULL;
    int i = 0, n = 0, *udp53 = NULL;

    prog = strdup ((x = strrchr (argv[0], '/')) != NULL ? x + 1 : argv[0]);

    sa.sa_handler = handle_term;
    sigaction (SIGINT, &sa, NULL);
    sigaction (SIGTERM, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction (SIGPIPE, &sa, NULL);

    i = check_option (argc, argv);
    argc -= i;
    argv += i;

    if (mode & DAEMON)
    {
        i = fork ();
        if (i == -1)
            err (-1, "could not fork a daemon process");
        if (i > 0)
            return 0;
    }

    time (&t);
    memset (buf, 0, sizeof (buf));
    strftime (buf, sizeof (buf), "%b-%d %Y %T %Z", localtime (&t));
    warnx ("version %s: starting: %s\n", VERSION, buf);

    set_timezone ();
    if (debug_level)
        warnx ("TIMEZONE: %s", env_get ("TZ"));

    initialize ();
    if (!debug_level)
        if ((x = env_get ("DEBUG_LEVEL")))
            debug_level = atol (x);
    warnx ("DEBUG_LEVEL set to `%d'", debug_level);

    if ((x = env_get ("DATALIMIT")))
    {
        struct rlimit r;
        unsigned long dlimit = atol (x);

        if (getrlimit (RLIMIT_DATA,  &r) != 0)
            err (-1, "could not get resource RLIMIT_DATA");

        r.rlim_cur = (dlimit <= r.rlim_max) ? dlimit : r.rlim_max;

        if (setrlimit (RLIMIT_DATA, &r) != 0)
            err (-1, "could not set resource RLIMIT_DATA");

        if (debug_level)
            warnx ("DATALIMIT set to `%ld' bytes", r.rlim_cur);
    }

    if (!(x = env_get ("IP")))
        err (-1, "$IP not set");
    for (i = 0; (unsigned)i < strlen (x); i++)
        n = (x[i] == ',') ? n+1 : n;
    if (!(udp53 = calloc (n+1, sizeof (int))))
        err (-1, "could not allocate enough memory for udp53");
    if (!(iop = calloc (n+1, sizeof (iopause_fd))))
        err (-1, "could not allocate enough memory for iop");

    i = n = 0;
    while (x[i])
    {
        unsigned int l = 0;

        if (!(l = ip4_scan(x+i, ip)))
            errx (-1, "could not parse IP address `%s'", x + i);

        udp53[n] = socket_udp();
        if (udp53[n] == -1)
            errx (-1, "could not open UDP socket");
        if (socket_bind4_reuse (udp53[n], ip, server_port) == -1)
            errx (-1, "could not bind UDP socket");

        ndelay_off (udp53[n]);
        socket_tryreservein (udp53[n], 65536);

        iop[n].fd = udp53[n];
        iop[n].events = IOPAUSE_READ;

        n++;
        i += (x[i + l] == ',') ? l + 1 : l;
    }

    droproot ();
    while (1)
    {
        struct taia stamp;
        struct in_addr odst; /* original destination IP */
        struct taia deadline;

        taia_now (&stamp);
        taia_uint (&deadline, 300);
        taia_add (&deadline, &deadline, &stamp);
        iopause (iop, n, &deadline, &stamp);

        for (i = 0; i < n; i++)
        {
            if (!iop[i].revents)
                continue;

            len = socket_recv4 (udp53[i], buf, sizeof (buf), ip, &port, &odst);
            if (len < 0)
                continue;
            if (!doit ())
                continue;
            if (response_len > 512)
                response_tc ();

            /* may block for buffer space; if it fails, too bad */
            len = socket_send4 (udp53[i], response,
                                response_len, ip, port, &odst);
            if (len < 0)
                continue;
            if (debug_level > 1)
                log_querydone(qnum, response, response_len);
        }
    }

    return 0;
}
예제 #14
0
static void
doit (void)
{
    struct taia stamp;
    struct taia deadline;
    int j = 0, r = 0, iolen = 0;

    for (;;)
    {
        taia_now (&stamp);
        taia_uint (&deadline, 120);
        taia_add (&deadline, &deadline, &stamp);

        iolen = 0;
        udp53io = io + iolen++;
        udp53io->fd = udp53;
        udp53io->events = IOPAUSE_READ;

        tcp53io = io + iolen++;
        tcp53io->fd = tcp53;
        tcp53io->events = IOPAUSE_READ;

        for (j = 0; j < MAXUDP; ++j)
        {
            if (u[j].active)
            {
                u[j].io = io + iolen++;
                query_io (&u[j].q, u[j].io, &deadline);
            }
        }

        for (j = 0; j < MAXTCP; ++j)
        {
            if (t[j].active)
            {
                t[j].io = io + iolen++;
                if (t[j].state == 0)
                    query_io (&t[j].q, t[j].io, &deadline);
                else
                {
                    if (taia_less (&t[j].timeout, &deadline))
                        deadline = t[j].timeout;
                    t[j].io->fd = t[j].tcp;
                    t[j].io->events = (t[j].state > 0) ?
                                            IOPAUSE_READ : IOPAUSE_WRITE;
                }
            }
        }
        iopause (io, iolen, &deadline, &stamp);

        for (j = 0; j < MAXUDP; ++j)
        {
            if (u[j].active)
            {
                r = query_get (&u[j].q, u[j].io, &stamp);
                if (r == -1)
                    u_drop (j);
                if (r == 1)
                    u_respond (j);
            }
        }
        for (j = 0; j < MAXTCP; ++j)
        {
            if (t[j].active)
            {
                if (t[j].io->revents)
                    t_timeout (j);
                if (t[j].state == 0)
                {
                    r = query_get (&t[j].q, t[j].io, &stamp);
                    if (r == -1)
                        t_drop (j);
                    if (r == 1)
                        t_respond (j);
                }
                else
                    if (t[j].io->revents || taia_less (&t[j].timeout, &stamp))
                        t_rw (j);
            }
        }

        if (udp53io && udp53io->revents)
                u_new();

        if (tcp53io && tcp53io->revents)
                t_new();
    }
}
예제 #15
0
void doit(int fdleft,int fdright) /* copy 0 -> fdleft, copy fdright -> 1 */
{
  struct taia stamp;
  struct taia deadline;
  iopause_fd x[4];
  int xlen;
  iopause_fd *io0;
  iopause_fd *ioleft;
  iopause_fd *io1;
  iopause_fd *ioright;
  int r;

  for (;;) {
    xlen = 0;

    io0 = 0;
    if (leftstatus == 0) {
      io0 = &x[xlen++];
      io0->fd = 0;
      io0->events = IOPAUSE_READ;
    }
    ioleft = 0;
    if (leftstatus == 1) {
      ioleft = &x[xlen++];
      ioleft->fd = fdleft;
      ioleft->events = IOPAUSE_WRITE;
    }

    ioright = 0;
    if (rightstatus == 0) {
      ioright = &x[xlen++];
      ioright->fd = fdright;
      ioright->events = IOPAUSE_READ;
    }
    io1 = 0;
    if (rightstatus == 1) {
      io1 = &x[xlen++];
      io1->fd = 1;
      io1->events = IOPAUSE_WRITE;
    }

    taia_now(&stamp);
    taia_uint(&deadline,3600);
    taia_add(&deadline,&stamp,&deadline);
    iopause(x,xlen,&deadline,&stamp);

    if (io0 && io0->revents) {
      r = read(0,leftbuf,sizeof leftbuf);
      if (r <= 0) {
        leftstatus = -1;
        close(fdleft);
        buffer_puts(&ssrecord,pid);
        buffer_puts(&ssrecord," < [EOF]\n");
        buffer_flush(&ssrecord);
      }
      else {
        leftstatus = 1; leftpos = 0; leftlen = r;
        record(leftbuf,r," < ");
      }
    }

    if (ioleft && ioleft->revents) {
      r = write(fdleft,leftbuf + leftpos,leftlen - leftpos);
      if (r == -1) break;
      leftpos += r;
      if (leftpos == leftlen) leftstatus = 0;
    }

    if (ioright && ioright->revents) {
      r = read(fdright,rightbuf,sizeof rightbuf);
      if (r <= 0) {
        buffer_puts(&ssrecord,pid);
        buffer_puts(&ssrecord," > [EOF]\n");
        buffer_flush(&ssrecord);
        break;
      }
      rightstatus = 1; rightpos = 0; rightlen = r;
      record(rightbuf,r," > ");
    }

    if (io1 && io1->revents) {
      r = write(1,rightbuf + rightpos,rightlen - rightpos);
      if (r == -1) break;
      rightpos += r;
      if (rightpos == rightlen) rightstatus = 0;
    }
  }

  _exit(0);
}
예제 #16
0
파일: s6-ftrigrd.c 프로젝트: bukzor/s6
int main (void)
{
  PROG = "s6-ftrigrd" ;

  if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ;
  if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ;
  if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ;

  {
    tain_t deadline ;
    tain_now_g() ;
    tain_addsec_g(&deadline, 2) ;
    if (!skaclient_server_01x_init_g(FTRIGR_BANNER1, FTRIGR_BANNER1_LEN, FTRIGR_BANNER2, FTRIGR_BANNER2_LEN, &deadline))
      strerr_diefu1sys(111, "sync with client") ;
  }

  for (;;)
  {
    iopause_fd x[3 + n] ;
    unsigned int i = 0 ;

    x[0].fd = 0 ; x[0].events = IOPAUSE_EXCEPT | IOPAUSE_READ ;
    x[1].fd = 1 ; x[1].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_1) ? 0 : IOPAUSE_WRITE) ;
    x[2].fd = unixmessage_sender_fd(unixmessage_sender_x) ;
    x[2].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_x) ? 0 : IOPAUSE_WRITE) ;
    for (; i < n ; i++)
    {
      a[i].xindex = 3 + i ;
      x[3+i].fd = a[i].trig.fd ;
      x[3+i].events = IOPAUSE_READ ;
    }

    if (iopause(x, 3 + n, 0, 0) < 0)
    {
      cleanup() ;
      strerr_diefu1sys(111, "iopause") ;
    }

   /* client closed */
    if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) break ;

   /* client is reading */
    if (x[1].revents & IOPAUSE_WRITE)
      if (!unixmessage_sender_flush(unixmessage_sender_1) && !error_isagain(errno))
      {
        cleanup() ;
        strerr_diefu1sys(111, "flush stdout") ;
      }
    if (x[2].revents & IOPAUSE_WRITE)
      if (!unixmessage_sender_flush(unixmessage_sender_x) && !error_isagain(errno))
      {
        cleanup() ;
        strerr_diefu1sys(111, "flush asyncout") ;
      }

   /* scan listening ftrigs */
    for (i = 0 ; i < n ; i++)
    {
      if (x[a[i].xindex].revents & IOPAUSE_READ)
        if (!ftrigio_read(a+i)) remove(i--) ;
    }

   /* client is writing */
    if (!unixmessage_receiver_isempty(unixmessage_receiver_0) || x[0].revents & IOPAUSE_READ)
    {
      if (unixmessage_handle(unixmessage_receiver_0, &parse_protocol, 0) < 0)
      {
        if (errno == EPIPE) break ; /* normal exit */
        cleanup() ;
        strerr_diefu1sys(111, "handle messages from client") ;
      }
    }
  }
  cleanup() ;
  return 0 ;
}
예제 #17
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
}
예제 #18
0
int main(int argc,char **argv)
{
  struct taia stamp;
  struct taia deadline;
  int opt;
  unsigned long u;
  int i;
  int j;
  int r;

  while ((opt = getopt(argc,argv,"c:l:")) != opteof)
    switch(opt) {
      case 'c':
	scan_ulong(optarg,&u);
	if (u < 1) u = 1;
	if (u > 1000) u = 1000;
	maxactive = u;
	break;
      case 'l':
	scan_ulong(optarg,&u);
	if (u < 1) u = 1;
	if (u > 1000000) u = 1000000;
	xmax = u;
	break;
      default:
	strerr_die1x(111,"dnsfilter: usage: dnsfilter [ -c concurrency ] [ -l lines ]");
    }

  x = (struct line *) alloc(xmax * sizeof(struct line));
  if (!x) nomem();
  byte_zero(x,xmax * sizeof(struct line));

  io = (iopause_fd *) alloc((xmax + 1) * sizeof(iopause_fd)); 
  if (!io) nomem();

  if (!stralloc_copys(&partial,"")) nomem();


  while (flag0 || inbuflen || partial.len || xnum) {
    taia_now(&stamp);
    taia_uint(&deadline,120);
    taia_add(&deadline,&deadline,&stamp);

    iolen = 0;

    if (flag0)
      if (inbuflen < sizeof inbuf) {
        inio = io + iolen++;
        inio->fd = 0;
        inio->events = IOPAUSE_READ;
      }

    for (i = 0;i < xnum;++i)
      if (x[i].flagactive) {
	x[i].io = io + iolen++;
	dns_transmit_io(&x[i].dt,x[i].io,&deadline);
      }

    iopause(io,iolen,&deadline,&stamp);

    if (flag0)
      if (inbuflen < sizeof inbuf)
        if (inio->revents) {
	  r = read(0,inbuf + inbuflen,(sizeof inbuf) - inbuflen);
	  if (r <= 0)
	    flag0 = 0;
	  else
	    inbuflen += r;
        }
    
    for (i = 0;i < xnum;++i)
      if (x[i].flagactive) {
	r = dns_transmit_get(&x[i].dt,x[i].io,&stamp);
	if (r == -1) {
	  errout(i);
	  x[i].flagactive = 0;
	  --numactive;
	}
	else if (r == 1) {
	  if (dns_name_packet(&x[i].middle,x[i].dt.packet,x[i].dt.packetlen) == -1)
	    errout(i);
	  if (x[i].middle.len)
	    if (!stralloc_cats(&x[i].left,"=")) nomem();
	  x[i].flagactive = 0;
	  --numactive;
	}
      }

    for (;;) {

      if (xnum && !x[0].flagactive) {
        buffer_put(buffer_1,x[0].left.s,x[0].left.len);
        buffer_put(buffer_1,x[0].middle.s,x[0].middle.len);
        buffer_put(buffer_1,x[0].right.s,x[0].right.len);
        buffer_flush(buffer_1);
        --xnum;
        tmp = x[0];
        for (i = 0;i < xnum;++i) x[i] = x[i + 1];
        x[xnum] = tmp;
	continue;
      }

      if ((xnum < xmax) && (numactive < maxactive)) {
        i = byte_chr(inbuf,inbuflen,'\n');
        if (inbuflen && (i == inbuflen)) {
	  if (!stralloc_catb(&partial,inbuf,inbuflen)) nomem();
	  inbuflen = 0;
	  continue;
        }

	if ((i < inbuflen) || (!flag0 && partial.len)) {
	  if (i < inbuflen) ++i;
	  if (!stralloc_catb(&partial,inbuf,i)) nomem();
	  inbuflen -= i;
	  for (j = 0;j < inbuflen;++j) inbuf[j] = inbuf[j + i];
  
	  if (partial.len) {
	    i = byte_chr(partial.s,partial.len,'\n');
	    i = byte_chr(partial.s,i,'\t');
	    i = byte_chr(partial.s,i,' ');
    
	    if (!stralloc_copyb(&x[xnum].left,partial.s,i)) nomem();
	    if (!stralloc_copys(&x[xnum].middle,"")) nomem();
	    if (!stralloc_copyb(&x[xnum].right,partial.s + i,partial.len - i)) nomem();
	    x[xnum].flagactive = 0;
  
	    partial.len = i;
	    if (!stralloc_0(&partial)) nomem();
	    if (ip4_scan(partial.s,ip)) {
	      dns_name4_domain(name,ip);
	      if (dns_resolvconfip(servers) == -1)
	        strerr_die2sys(111,FATAL,"unable to read /etc/resolv.conf: ");
	      if (dns_transmit_start(&x[xnum].dt,servers,1,name,DNS_T_PTR,"\0\0\0\0") == -1)
	        errout(xnum);
	      else {
	        x[xnum].flagactive = 1;
	        ++numactive;
	      }
	    }
	    ++xnum;
	  }
  
	  partial.len = 0;
	  continue;
	}
      }

      break;
    }
  }

  _exit(0);
}
예제 #19
0
int main (void)
{
  stralloc indata = STRALLOC_ZERO ;
  unsigned int instate = 0 ;
  PROG = "s6-ftrigrd" ;

  if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ;
  if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ;
  if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ;

  {
    struct taia deadline, stamp ;
    taia_now(&stamp) ;
    taia_addsec(&deadline, &stamp, 2) ;
    if (!skaserver2_sync(&asyncout, FTRIGR_BANNER1, FTRIGR_BANNER1_LEN, FTRIGR_BANNER2, FTRIGR_BANNER2_LEN, &deadline, &stamp))
      strerr_diefu1sys(111, "sync with client") ;
  }

  for (;;)
  {
    register unsigned int n = genalloc_len(ftrigio_t, &a) ;
    iopause_fd x[3 + n] ;
    unsigned int i = 0 ;
    int r ;

    x[0].fd = 0 ; x[0].events = IOPAUSE_EXCEPT | IOPAUSE_READ ;
    x[1].fd = 1 ; x[1].events = IOPAUSE_EXCEPT | (bufalloc_len(bufalloc_1) ? IOPAUSE_WRITE : 0) ;
    x[2].fd = bufalloc_fd(&asyncout) ; x[2].events = IOPAUSE_EXCEPT | (bufalloc_len(&asyncout) ? IOPAUSE_WRITE : 0) ;
    for (; i < n ; i++)
    {
      register ftrigio_t_ref p = genalloc_s(ftrigio_t, &a) + i ;
      p->xindex = 3 + i ;
      x[3+i].fd = p->trig.fd ;
      x[3+i].events = IOPAUSE_READ ;
    }

    r = iopause(x, 3 + n, 0, 0) ;
    if (r < 0)
    {
      cleanup() ;
      strerr_diefu1sys(111, "iopause") ;
    }

   /* client closed => exit */
    if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) break ;

   /* client reading => flush pending data */
    if (x[1].revents & IOPAUSE_WRITE)
      if ((bufalloc_flush(bufalloc_1) == -1) && !error_isagain(errno))
      {
        cleanup() ;
        strerr_diefu1sys(111, "flush stdout") ;
      }
    if (x[2].revents & IOPAUSE_WRITE)
      if ((bufalloc_flush(&asyncout) == -1) && !error_isagain(errno))
      {
        cleanup() ;
        strerr_diefu1sys(111, "flush asyncout") ;
      }

   /* scan listening ftrigs */
    for (i = 0 ; i < genalloc_len(ftrigio_t, &a) ; i++)
    {
      register ftrigio_t_ref p = genalloc_s(ftrigio_t, &a) + i ;
      if (x[p->xindex].revents & IOPAUSE_READ)
      {
        char c ;
        register int r = sanitize_read(fd_read(p->trig.fd, &c, 1)) ;
        if (!r) continue ;
        if (r < 0)
        {
          trig(p->id, 'd', errno) ;
          remove(i--) ;
        }
        else if (!sredfa_feed(p->re, &p->dfastate, c))
        {
          trig(p->id, 'd', ENOEXEC) ;
          remove(i--) ;
        }
        else if (p->dfastate & SREDFA_ACCEPT)
        {
          trig(p->id, '!', c) ;
          if (p->options & FTRIGR_REPEAT)
            p->dfastate = SREDFA_START ;
          else remove(i--) ;
        }
      }
    }

   /* client writing => get data and parse it */
    if (buffer_len(buffer_0small) || x[0].revents & IOPAUSE_READ)
    {
      int r ;
      for (;;)
      {
        uint16 id ;
        r = sanitize_read(netstring_get(buffer_0small, &indata, &instate)) ;
        if (r <= 0) break ;
        if (indata.len < 3)
        {
          cleanup() ;
          strerr_dief1x(100, "invalid client request") ;
        }
        uint16_unpack_big(indata.s, &id) ;
        switch (indata.s[2])  /* protocol parsing */
        {
          case 'U' : /* unsubscribe */
          {
            register unsigned int i = genalloc_len(ftrigio_t, &a) ;
            for (; i ; i--) if (genalloc_s(ftrigio_t, &a)[i-1].id == id) break ;
            if (i) remove(i-1) ;
            answer(0) ;
            break ;
          }
          case 'L' : /* subscribe to path and match re */
          {
            ftrigio_t f = FTRIGIO_ZERO ;
            uint32 pathlen, relen ;
            if (indata.len < 18)
            {
              answer(EPROTO) ;
              break ;
            }
            uint32_unpack_big(indata.s + 3, &f.options) ;
            uint32_unpack_big(indata.s + 7, &pathlen) ;
            uint32_unpack_big(indata.s + 11, &relen) ;
            if (((pathlen + relen + 16) != indata.len) || indata.s[15 + pathlen])
            {
              answer(EPROTO) ;
              break ;
            }
            f.id = id ;
            if (!stralloc_0(&indata))
            {
              answer(errno) ;
              break ;
            }
            f.re = sredfa_new() ;
            if (!f.re)
            {
              answer(errno) ;
              break ;
            }
            if (!sredfa_from_regexp(f.re, indata.s + 16 + pathlen)
             || !ftrig1_make(&f.trig, indata.s + 15))
            {
              sredfa_delete(f.re) ;
              answer(errno) ;
              break ;
            }
            if (!genalloc_append(ftrigio_t, &a, &f))
            {
              ftrigio_deepfree(&f) ;
              answer(errno) ;
              break ;
            }
            answer(0) ;
            break ;
          }
          default :
          {
            cleanup() ;
            strerr_dief1x(100, "invalid client request") ;
          }
        }
        indata.len = 0 ;
      } /* end loop: parse input from client */

      if (r < 0)
      {
        if (errno == EPIPE) break ; /* client closed */
        else
        {
          cleanup() ;
          strerr_diefu1sys(111, "read a netstring") ;
        }
      } 
    } /* end if: stuff to read on stdin */
  } /* end loop: main iopause */

  cleanup() ;
  return 0 ;
}
예제 #20
0
파일: ssl_io.c 프로젝트: alexgirao/ipsvd
void doio(void) {
  iopause_fd x[2];
  struct taia deadline;
  struct taia now;
  struct taia timeout;

  if (! stralloc_ready(&encinbuf, bufsizein)) die_nomem();
  encin.buf =encin.start =encin.end =encinbuf.s; encin.size =bufsizein;
  if (! stralloc_ready(&decinbuf, bufsizein)) die_nomem();
  decin.buf =decin.start =decin.end =decinbuf.s; decin.size =bufsizein;
  if (! stralloc_ready(&encoubuf, bufsizeou)) die_nomem();
  encou.buf =encou.start =encou.end =encoubuf.s; encou.size =bufsizeou;
  if (! stralloc_ready(&decoubuf, bufsizeou)) die_nomem();
  decou.buf =decou.start =decou.end =decoubuf.s; decou.size =bufsizeou;

  if (client) {
    rc =matrixSslEncodeClientHello(ssl, &decou, 0);
    if (rc != 0) fatalx("unable to encode client hello");
    if (write(fdstdou, decou.start, decou.end -decou.start)
        != (decou.end -decou.start))
      fatal("unable to send client hello");
    if (verbose > 2) info("sending client hello");
    if (verbose > 2) infou("write bytes: ", decou.end -decou.start);
    bytesou +=decou.end -decou.start;
    decou.start =decou.end =decou.buf;
  }

  taia_now(&now);
  taia_uint(&timeout, handshake_timeout);
  taia_add(&timeout, &now, &timeout);

  for (;;) {
    iopause_fd *xx =x;
    int l =2;

    x[0].fd =encpipe[0];
    x[0].events =IOPAUSE_READ;
    x[0].revents =0;
    x[1].fd =fdstdin;
    x[1].events =IOPAUSE_READ;
    x[1].revents =0;

    if ((x[0].fd == -1) || handshake) { --l; ++xx; }
    if (x[1].fd == -1) --l;
    if (! l) return;

    taia_now(&now);
    if (handshake) {
      if (taia_less(&timeout, &now)) {
        if (verbose) info("ssl handshake timeout, exit.");
        return;
      }
      deadline.sec =timeout.sec;
      deadline.nano =timeout.nano;
      deadline.atto =timeout.atto;
    }
    else {
      taia_uint(&deadline, 30);
      taia_add(&deadline, &now, &deadline);
    }
    iopause(xx, l, &deadline, &now);
    
    if (x[0].revents) encode();
    if (x[1].revents) decode();
  }
}
예제 #21
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;
      }
  }
}
예제 #22
0
void doit(int fdleft,int fdright)
{
  struct taia stamp;
  struct taia deadline;
  iopause_fd x[4];
  int xlen;
  iopause_fd *io0;
  iopause_fd *ioleft;
  iopause_fd *io1;
  iopause_fd *ioright;
  int r;
  int i;
  char ch;

  for (;;) {
    xlen = 0;

    io0 = 0;
    if (leftstatus == 0) {
      io0 = &x[xlen++];
      io0->fd = 0;
      io0->events = IOPAUSE_READ;
    }
    ioleft = 0;
    if (leftstatus == 1) {
      ioleft = &x[xlen++];
      ioleft->fd = fdleft;
      ioleft->events = IOPAUSE_WRITE;
    }

    ioright = 0;
    if (rightstatus == 0) {
      ioright = &x[xlen++];
      ioright->fd = fdright;
      ioright->events = IOPAUSE_READ;
    }
    io1 = 0;
    if (rightstatus == 1) {
      io1 = &x[xlen++];
      io1->fd = 1;
      io1->events = IOPAUSE_WRITE;
    }

    taia_now(&stamp);
    taia_uint(&deadline,3600);
    taia_add(&deadline,&stamp,&deadline);
    iopause(x,xlen,&deadline,&stamp);

    if (io0 && io0->revents) {
      r = read(0,prebuf,sizeof prebuf);
      if (r <= 0) {
        leftstatus = -1;
        close(fdleft);
      }
      else {
        leftstatus = 1;
    leftpos = 0;
    leftlen = 0;
    for (i = 0;i < r;++i) {
      ch = prebuf[i];
      if (ch == '\n')
        if (!leftflagcr)
          leftbuf[leftlen++] = '\r';
      leftbuf[leftlen++] = ch;
      leftflagcr = (ch == '\r');
    }
      }
    }

    if (ioleft && ioleft->revents) {
      r = write(fdleft,leftbuf + leftpos,leftlen - leftpos);
      if (r == -1) break;
      leftpos += r;
      if (leftpos == leftlen) leftstatus = 0;
    }

    if (ioright && ioright->revents) {
      r = read(fdright,prebuf,sizeof prebuf);
      if (r <= 0) break;
      rightstatus = 1;
      rightpos = 0;
      rightlen = 0;
      for (i = 0;i < r;++i) {
    ch = prebuf[i];
    if (ch == '\n')
      if (!rightflagcr)
        rightbuf[rightlen++] = '\r';
    rightbuf[rightlen++] = ch;
    rightflagcr = (ch == '\r');
      }
    }

    if (io1 && io1->revents) {
      r = write(1,rightbuf + rightpos,rightlen - rightpos);
      if (r == -1) break;
      rightpos += r;
      if (rightpos == rightlen) rightstatus = 0;
    }
  }

  _exit(0);
}
예제 #23
0
int main(int argc,char * const *argv) {
  int opt;
  const char *path;
  mode_t m;
  iopause_fd x;
  struct taia deadline;
  struct taia stamp;
  int pid = 0;
  char ch;
  int wstat;

  while ((opt = getopt(argc,argv,"wWdDt:")) != opteof)
    switch(opt) {
      case 't': scan_uint(optarg,&timeout); break;
      case 'w': flagwait = 1; break;
      case 'W': flagwait = 0; break;
      case 'd': flagdelete = 1; break;
      case 'D': flagdelete = 0; break;
      default: usage();
    }

  argv += optind;
  path = *argv++;
  if (!path) usage();

  if (flagdelete) {
    m = umask(0);
    unlink(path);
    fifo_make(path,0666);
    umask(m);
  }

  fdr = open_read(path);
  if (fdr == -1)
    strerr_die4sys(111,FATAL,"cannot read ",path,": ");
  ndelay_on(fdr);

  fdw = open_write(path);
  if (fdw == -1)
    strerr_die4sys(111,FATAL,"cannot write ",path,": ");

  if (*argv) {
    pid = fork();
    switch (pid) {
      case 0:
	close(fdr); close(fdw);
	pathexec(argv);
	strerr_die4sys(111,FATAL,"cannot run ",*argv,": ");
      case -1:
	strerr_die4sys(111,FATAL,"cannot fork ",*argv,": ");
	break;
      default:
	break;
    }
  }
  else
    flagwait = 0;

  x.fd = fdr;
  x.events = IOPAUSE_READ;
  taia_now(&stamp);
  taia_uint(&deadline,timeout);
  taia_add(&deadline,&stamp,&deadline);

  for (;;) {
    taia_now(&stamp);
    iopause(&x,1,&deadline,&stamp);
    if (x.revents) {
      waiting = 0;
      break;
    }
    if (taia_less(&deadline,&stamp)) {
      waiting = 99;
      break;
    }
  }

  if (!waiting)
    if (read(fdr,&ch,1) != 1)
      waiting = 0;

  if (flagwait)
    if (wait_pid(&wstat,pid) != pid)
      strerr_die2x(111,FATAL,"cannot reap child process");

  _exit(waiting);
}