#include #include "strerr.h" #include "error.h" #include "sgetopt.h" #include "scan.h" #include "stralloc.h" #include "buffer.h" #include "pathexec.h" #include "fd.h" #include "wait.h" #include "taia.h" #include "iopause.h" #include "ndelay.h" #include "sig.h" /* defaults */ #define TIMEOUT 300 #define SIZEMAX 1024 #define USAGE " [-vo] [-t timeout] [-s size] prog" #define WARNING "uncat: warning: " #define FATAL "uncat: fatal: " const char *progname; int exitasap =0; void exit_asap() { exitasap =1; } void usage () { strerr_die4x(1, "usage: ", progname, USAGE, "\n"); } int main (int argc, const char * const *argv, const char * const *envp) { int opt; unsigned long timeout =TIMEOUT; unsigned long sizemax =SIZEMAX; int verbose =0; int once =0; static stralloc sa; int eof =0; progname =*argv; sig_block(sig_term); sig_catch(sig_term, exit_asap); while ((opt =getopt(argc, argv, "t:s:voV")) != opteof) { switch(opt) { case 'V': strerr_warn1("$Id: uncat.c,v 1.8 2004/02/28 15:52:00 pape Exp $\n", 0); case '?': usage(); case 't': scan_ulong(optarg, &timeout); if (timeout <= 0) timeout =TIMEOUT; break; case 's': scan_ulong(optarg, &sizemax); if (sizemax <= 0) sizemax =SIZEMAX; break; case 'v': verbose =1; break; case 'o': once =1; break; } } argv +=optind; if (!*argv) usage(); if (verbose) strerr_warn2(WARNING, "starting.", 0); ndelay_on(0); for (;;) { struct taia now, deadline; int cpipe[2]; int pid; int wstat; stralloc_copys(&sa, ""); /* set timeout */ taia_now(&now); taia_uint(&deadline, timeout); taia_add(&deadline, &now, &deadline); /* read fd 0, stop at maxsize bytes or timeout */ for (;;) { int r; char *s; iopause_fd iofd; taia_now(&now); if (taia_less(&deadline, &now)) { if (verbose && sa.len) strerr_warn2(WARNING, "timeout reached.", 0); break; } iofd.fd =0; iofd.events =IOPAUSE_READ; sig_unblock(sig_term); iopause(&iofd, 1, &deadline, &now); sig_block(sig_term); if (exitasap) { if (verbose) strerr_warn2(WARNING, "got sigterm.", 0); break; } r =buffer_feed(buffer_0); if (r < 0) { if (errno == error_again) continue; strerr_die2sys(111, FATAL, "unable to read fd 0: "); } if (r == 0) { if (verbose) strerr_warn2(WARNING, "end of input.", 0); if (! once) continue; eof++; break; } if (r >= sizemax) r =sizemax; if ((sa.len +r) > sizemax) { if (verbose) strerr_warn2(WARNING, "max size reached.", 0); break; } s =buffer_peek(buffer_0); if (! stralloc_catb(&sa, s, r)) { strerr_die2sys(111, FATAL, "out of memory: "); } buffer_seek(buffer_0, r); } if (sa.len) { /* run prog to process sa.s */ if (pipe(cpipe) == -1) { strerr_die2sys(111, FATAL, "unable to create pipe for child: "); } while ((pid =fork()) == -1) { strerr_warn4(WARNING, "unable to fork for \"", *argv, "\" pausing: ", &strerr_sys); sleep(5); } if (!pid) { /* child */ sig_uncatch(sig_term); sig_unblock(sig_term); close(cpipe[1]); fd_move(0, cpipe[0]); fd_copy(1, 2); if (verbose) strerr_warn2(WARNING, "starting child.", 0); pathexec_run(*argv, argv, envp); strerr_die2sys(111, FATAL, "unable to start child: "); } close(cpipe[0]); if (write(cpipe[1], sa.s, sa.len) < sa.len) { strerr_warn2(WARNING, "unable to write to child: ", &strerr_sys); } close(cpipe[1]); if (wait_pid(&wstat, pid) != pid) { strerr_die2sys(111, FATAL, "wait_pid: "); } if (wait_crashed(wstat)) { strerr_warn2(WARNING, "child crashed.", 0); } else { if (verbose) strerr_warn2(WARNING, "child exited.", 0); } } if (exitasap || eof) break; } if (verbose) strerr_warn2(WARNING, "exit.", 0); _exit(0); }