#define F_DAEMON 1u
#define F_INIT 2u
+#define F_FOREGROUND 4u
#define T_RESOLVE SEC(30)
#define T_PING SEC(5)
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);
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@ --- *
{
admin *a = vp;
const acmd *c;
- char *av[16];
+ char *av[16 + 1];
size_t ac;
TIMER;
}
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--;
/* --- @a_init@ --- *
*
* Arguments: @const char *name@ = socket name to create
+ * @uid_t u@ = user to own the socket
+ * @gid_t g@ = group to own the socket
*
* Returns: ---
*
* Use: Creates the admin listening socket.
*/
-void a_init(const char *name)
+void a_init(const char *name, uid_t u, gid_t g)
{
int fd;
int n = 5;
goto again;
}
chmod(sun.sun_path, 0600);
+ if (chown(sun.sun_path, u, g)) {
+ T( trace(T_ADMIN,
+ "admin: failed to give away socket: %s",
+ strerror(errno)); )
+ }
fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
if (listen(fd, 5))
die(EXIT_FAILURE, "couldn't listen on socket: %s", strerror(errno));