X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/2b3ef39558d9aa6c187dc088c81a5b9872984d3c..c3897a7de7a53dab3f96fb224fa90dd35fa56dc1:/client/tripectl.c diff --git a/client/tripectl.c b/client/tripectl.c index 4c8dde5a..95f95f44 100644 --- a/client/tripectl.c +++ b/client/tripectl.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include #include @@ -91,6 +93,7 @@ static const char *bgtag = 0; #define f_noinput 64u #define f_warn 128u #define f_uclose 256u +#define f_losing 512u /*----- Main code ---------------------------------------------------------*/ @@ -120,7 +123,7 @@ static void checkbg(char **p) die(EXIT_FAILURE, "unexpected background tag `%s'", q); } -static void dolog(int prio, const char *msg, ...) +static void PRINTF_LIKE(2, 3) dolog(int prio, const char *msg, ...) { va_list ap; dstr d = DSTR_INIT; @@ -132,14 +135,14 @@ static void dolog(int prio, const char *msg, ...) if (f & f_syslog) syslog(prio, "%s", d.buf); if (logfp) { switch (prio) { - case LOG_WARN: cat = "warning"; break; + case LOG_WARNING: cat = "warning"; break; case LOG_DEBUG: cat = "debug"; break; case LOG_ERR: cat = "error"; break; default: cat = "message"; break; } writelog(cat, d.buf); } - if (prio == LOG_WARN && (f & f_warn)) + if (prio == LOG_WARNING && (f & f_warn)) fprintf(stderr, "Warning: %s\n", d.buf); dstr_destroy(&d); } @@ -153,15 +156,16 @@ static void cline(char *p, size_t len, void *b) if (!p) { if (f & f_command) die(EXIT_FAILURE, "server dropped the connection"); + f &= ~f_losing; exit(0); } q = str_getword(&p); if (!q) return; if (strcmp(q, "WARN") == 0) - dolog(LOG_WARNING, p); + dolog(LOG_WARNING, "%s", p); else if (strcmp(q, "TRACE") == 0) - dolog(LOG_DEBUG, p); + dolog(LOG_DEBUG, "%s", p); else if (!(f & f_command)) dolog(LOG_ERR, "unexpected output `%s %s'", q, p); else if (strcmp(q, "FAIL") == 0) { @@ -217,6 +221,16 @@ static void uline(char *p, size_t len, void *b) } } +static void eline(char *p, size_t len, void *b) +{ + if (p) + dolog(LOG_WARNING, "(stderr): %s", p); + else { + selbuf_destroy(b); + close(fd); + } +} + static void setup(const char *cmd) { dstr d = DSTR_INIT; @@ -271,9 +285,9 @@ static void logfile(const char *name) if (logfp) writelog("error", d.buf); else if (logname) - die(EXIT_FAILURE, d.buf); + die(EXIT_FAILURE, "%s", d.buf); if (f & f_syslog) - syslog(LOG_ERR, d.buf); + syslog(LOG_ERR, "%s", d.buf); dstr_destroy(&d); } } @@ -285,7 +299,7 @@ static void cleanup(void) { if (pidfile) unlink(pidfile); } static void sigdie(int sig) { cleanup(); signal(sig, SIG_DFL); raise(sig); } -static void putarg(string_v *av, const char *fmt, ...) +static void PRINTF_LIKE(2, 3) putarg(string_v *av, const char *fmt, ...) { va_list ap; dstr d = DSTR_INIT; @@ -356,12 +370,13 @@ int main(int argc, char *argv[]) size_t sz; uid_t u = -1; gid_t g = -1; - int pfd[2]; + int pfd[2], efd[2]; + mdup_fd md[3]; pid_t kid; struct sigaction sa; sigset_t newmask, oldmask; struct sockaddr_un sun; - selbuf bu, bs; + selbuf bu, bs, be; dstr d = DSTR_INIT; sig hup; @@ -465,8 +480,6 @@ int main(int argc, char *argv[]) die(EXIT_FAILURE, "couldn't set `%s' as current directory: %s", dir, strerror(errno)); } - if (logname) - logfile(logname); if (!pidfile && (f & f_daemon) && ((f & f_syslog) || logname)) pidfile = "tripectl.pid"; if (pidfile && (pidfp = fopen(pidfile, "w")) == 0) { @@ -498,7 +511,7 @@ int main(int argc, char *argv[]) putarg(&spawnopts, "-d."); putarg(&spawnopts, "-F"); putarg(&spawnopts, "%s", spawnpath); - if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfd)) + if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfd) || pipe(efd)) die(EXIT_FAILURE, "error from socketpair: %s", strerror(errno)); sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); @@ -506,11 +519,12 @@ int main(int argc, char *argv[]) if ((kid = fork()) < 0) die(EXIT_FAILURE, "fork failed: %s", strerror(errno)); if (!kid) { - dup2(pfd[1], STDIN_FILENO); - dup2(pfd[1], STDOUT_FILENO); - close(pfd[0]); - close(pfd[1]); - if (logfp) fclose(logfp); + close(pfd[0]); close(efd[0]); + sigprocmask(SIG_SETMASK, &oldmask, 0); + md[0].cur = pfd[1]; md[0].want = STDIN_FILENO; + md[1].cur = pfd[1]; md[1].want = STDOUT_FILENO; + md[2].cur = efd[1]; md[2].want = STDERR_FILENO; + mdup(md, 3); if (pidfp) fclose(pidfp); closelog(); if (f & f_daemon) detachtty(); @@ -519,7 +533,8 @@ int main(int argc, char *argv[]) } sigprocmask(SIG_SETMASK, &oldmask, 0); fd = pfd[0]; - close(pfd[1]); + close(pfd[1]); close(efd[1]); + selbuf_init(&be, &sel, efd[0], eline, &be); } else { sz = strlen(sock) + 1; if (sz > sizeof(sun.sun_path)) @@ -536,7 +551,10 @@ int main(int argc, char *argv[]) } } + f |= f_losing; /* pessimism */ u_setugid(u, g); + if (logname) + logfile(logname); if (f & f_daemon) { if (daemonize()) die(EXIT_FAILURE, "error becoming daemon: %s", strerror(errno));