X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/2d752320d61b46a65ebb9fa754033f250f097cd3..452bf3f6897b8c6a22b51e1ef228da39136d51a7:/client.c diff --git a/client.c b/client.c index 7edc790b..4aece8d1 100644 --- a/client.c +++ b/client.c @@ -79,6 +79,7 @@ static const char *logname = 0; static FILE *logfp = 0; static unsigned f = 0; static int fd; +static const char *bgtag = 0; #define f_bogus 1u #define f_spawn 2u @@ -109,6 +110,21 @@ static void writelog(const char *cat, const char *msg) fprintf(logfp, "%s %s: %s\n", buf, cat, msg); } +static void checkbg(char **p) +{ + char *q = str_getword(p); + if (!q) + die(EXIT_FAILURE, "missing background tag"); + if (!bgtag || strcmp(bgtag, q) != 0) + die(EXIT_FAILURE, "unexpected background tag `%s'", q); +} + +static void checkfg(void) +{ + if (bgtag) + die(EXIT_FAILURE, "unexpected foreground response"); +} + static void cline(char *p, size_t len, void *b) { char *q; @@ -141,13 +157,29 @@ static void cline(char *p, size_t len, void *b) writelog("error", d.buf); dstr_destroy(&d); } - } else if (strcmp(q, "FAIL") == 0) + } else if (strcmp(q, "FAIL") == 0) { + checkfg(); die(EXIT_FAILURE, "%s", p); - else if (strcmp(q, "INFO") == 0) + } else if (strcmp(q, "INFO") == 0) { + checkfg(); puts(p); - else if (strcmp(q, "OK") == 0) + } else if (strcmp(q, "OK") == 0) { + checkfg(); + exit(0); + } else if (strcmp(q, "BGDETACH") == 0) { + if (bgtag) + die(EXIT_FAILURE, "repeat detach"); + bgtag = xstrdup(p); + } else if (strcmp(q, "BGOK") == 0) { + checkbg(&p); exit(0); - else + } else if (strcmp(q, "BGINFO") == 0) { + checkbg(&p); + puts(p); + } else if (strcmp(q, "BGFAIL") == 0) { + checkbg(&p); + die(EXIT_FAILURE, "%s", p); + } else die(EXIT_FAILURE, "unexpected output `%s %s'", q, p); } @@ -169,7 +201,48 @@ static void uline(char *p, size_t len, void *b) f |= f_uclose; } else { p[len] = '\n'; - write(fd, p, len + 1); + errno = EIO; + if (write(fd, p, len + 1) != len + 1) + moan("write failed: %s", strerror(errno)); + } +} + +static void setup(const char *cmd) +{ + dstr d = DSTR_INIT; + char ch; + char *p, *q; + int n; + + dstr_puts(&d, cmd); + dstr_putc(&d, '\n'); + errno = EIO; /* Relax: be vague */ + if (write(fd, d.buf, d.len) != d.len) { + die(EXIT_FAILURE, "error sending setup command `%s': %s", + cmd, strerror(errno)); + } + dstr_reset(&d); + for (;;) { + n = read(fd, &ch, 1); + if (!n) + die(EXIT_FAILURE, "unexpected EOF during setup"); + if (n < 0) { + die(EXIT_FAILURE, "error receiving reply to `%s': %s", + cmd, strerror(errno)); + } + if (d.len < 256) + dstr_putc(&d, ch); + if (ch == '\n') { + p = d.buf; + q = str_getword(&p); + if (!q) + ; + else if (strcmp(q, "OK") == 0) + return; + else if (strcmp(q, "FAIL") == 0) + die(EXIT_FAILURE, "setup command `%s' failed: %s", cmd, p); + dstr_reset(&d); + } } } @@ -245,7 +318,7 @@ Options in full:\n\ \n\ -D, --daemon Become a background task after connecting.\n\ -d, --directory=DIR Select current directory [default " CONFIGDIR "].\n\ --a, --admin-socket=FILE Select socket to connect to +-a, --admin-socket=FILE Select socket to connect to\n\ [default " SOCKETDIR "/tripesock].\n\ -P, --pidfile=FILE Write process-id to FILE.\n\ \n\ @@ -440,9 +513,12 @@ int main(int argc, char *argv[]) fprintf(pidfp, "%li\n", (long)getpid()); fclose(pidfp); } + signal(SIGPIPE, SIG_IGN); /* --- If we're meant to be interactive, do that --- */ + if (optind == argc) + setup("WATCH -A+tw"); if (!(f & f_noinput) && optind == argc) { sel_state sel; selbuf bu, bs; @@ -460,14 +536,16 @@ int main(int argc, char *argv[]) if (optind < argc) { dstr d = DSTR_INIT; + setup((f & f_warn) ? "WATCH -A+w" : "WATCH -A"); dstr_puts(&d, argv[optind++]); while (optind < argc) { dstr_putc(&d, ' '); dstr_puts(&d, argv[optind++]); } dstr_putc(&d, '\n'); - write(fd, d.buf, d.len); - shutdown(fd, 1); + errno = EIO; + if (write(fd, d.buf, d.len) != d.len || shutdown(fd, 1)) + die(EXIT_FAILURE, "write failed: %s", strerror(errno)); dstr_destroy(&d); f |= f_command; }