/* -*-c-*-
*
- * $Id: client.c,v 1.14 2004/04/08 01:36:17 mdw Exp $
+ * $Id$
*
* Client for TrIPE
*
static FILE *logfp = 0;
static unsigned f = 0;
static int fd;
+static const char *bgtag = 0;
#define f_bogus 1u
#define f_spawn 2u
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;
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);
}
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);
+ }
}
}
{
pquis(fp, "\
Usage:\n\
- $ [-w] [-options] [command [args]...]\n\
- $ [-Dl] [-f file] [-options]\n\
+ $ [-w] [-OPTIONS] [COMMAND [ARGS]...]\n\
+ $ [-Dl] [-f FILE] [-OPTIONS]\n\
Options:\n\
- [-s] [-d directory] [-a socket] [-P pidfile]\n\
- [-p program] [-S arg,arg,...]\n\
+ [-s] [-d DIRECTORY] [-a SOCKET] [-P PIDFILE]\n\
+ [-p PROGRAM] [-S ARG,ARG,...]\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\
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;
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;
}