X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/blobdiff_plain/c8e02c8a4947afa4f9ac20e78a3c8808b3945804..a50f9a0eaed03dfe85ff3d7a4c24da20ac705dae:/server/admin.c diff --git a/server/admin.c b/server/admin.c index 288a64ff..c4433e45 100644 --- a/server/admin.c +++ b/server/admin.c @@ -70,6 +70,7 @@ static sig s_term, s_int, s_hup; #define F_DAEMON 1u #define F_INIT 2u +#define F_FOREGROUND 4u #define T_RESOLVE SEC(30) #define T_PING SEC(5) @@ -1061,7 +1062,7 @@ static void a_resolve(admin *a, admin_resop *r, const char *tag, r->sa.sin.sin_family = AF_INET; r->sasz = sizeof(r->sa.sin); r->addr = xstrdup(av[i]); - if (!av[i + i]) + if (!av[i + 1]) pt = TRIPE_PORT; else { pt = strtoul(av[i + 1], &p, 0); @@ -1912,53 +1913,66 @@ static void acmd_help(admin *a, unsigned ac, char *av[]) static void a_destroypending(void) { - admin *a, *aa; + admin *a, *aa, *head; admin_bgop *bg, *bbg; admin_service *svc, *ssvc; - /* --- Destroy connections marked as pending --- */ + /* --- Destroy connections marked as pending --- * + * + * Slightly messy. Killing clients may cause others to finally die. Make + * sure that they can be put on the list without clobbering anything or + * getting lost. + */ - for (a = a_dead; a; a = aa) { - aa = a->next; - assert(a->f & AF_DEAD); + while (a_dead) { + head = a_dead; + a_dead = 0; + for (a = head; a; a = aa) { + aa = a->next; + assert(a->f & AF_DEAD); - /* --- Report what we're doing --- */ + /* --- Report what we're doing --- */ - T( trace(T_ADMIN, "admin: completing destruction of connection %u", - a->seq); ) + T( trace(T_ADMIN, "admin: completing destruction of connection %u", + a->seq); ) - /* --- Abort any background jobs in progress --- */ + /* --- If this is the foreground client then shut down --- */ - for (bg = a->bg; bg; bg = bbg) { - bbg = bg->next; - bg->cancel(bg); - if (bg->tag) xfree(bg->tag); - xfree(bg); - } + if (a->f & AF_FOREGROUND) { + T( trace(T_ADMIN, "admin: foreground client quit: shutting down"); ) + a_warn("SERVER", "quit", "foreground-eof", A_END); + a_quit(); + } - /* --- Release services I hold, and abort pending jobs --- */ + /* --- Abort any background jobs in progress --- */ - for (svc = a->svcs; svc; svc = ssvc) { - ssvc = svc->next; - a_svcrelease(svc); - } - a_jobtablefinal(&a->j); + for (bg = a->bg; bg; bg = bbg) { + bbg = bg->next; + bg->cancel(bg); + if (bg->tag) xfree(bg->tag); + xfree(bg); + } - /* --- Close file descriptors and selectory --- */ + /* --- Release services I hold, and abort pending jobs --- */ - selbuf_destroy(&a->b); - if (a->b.reader.fd != a->w.fd) close(a->b.reader.fd); - close(a->w.fd); - if (a_stdin == a) a_stdin = 0; + for (svc = a->svcs; svc; svc = ssvc) { + ssvc = svc->next; + a_svcrelease(svc); + } + a_jobtablefinal(&a->j); - /* --- Done --- */ + /* --- Close file descriptors and selectory --- */ - DESTROY(a); - } + selbuf_destroy(&a->b); + if (a->b.reader.fd != a->w.fd) close(a->b.reader.fd); + close(a->w.fd); + if (a_stdin == a) a_stdin = 0; - /* --- All pending destruction completed --- */ + /* --- Done --- */ - a_dead = 0; + DESTROY(a); + } + } } /* --- @a_destroy@ --- * @@ -2016,7 +2030,7 @@ static void a_line(char *p, size_t len, void *vp) { admin *a = vp; const acmd *c; - char *av[16]; + char *av[16 + 1]; size_t ac; TIMER; @@ -2031,9 +2045,10 @@ static void a_line(char *p, size_t len, void *vp) } return; } - ac = str_qsplit(p, av, 16, 0, STRF_QUOTE); + ac = str_qsplit(p, av, N(av) - 1, 0, STRF_QUOTE); if (!ac) return; + av[ac] = 0; for (c = acmdtab; c->name; c++) { if (mystrieq(av[0], c->name)) { ac--;