chiark / gitweb /
admin: Improve handling of background jobs.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 1 Jan 2007 12:52:32 +0000 (12:52 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 1 Jan 2007 12:52:32 +0000 (12:52 +0000)
New commands BGCANCEL (cancel an outstanding job) and JOBS (list
outstanding jobs).

doc/tripe-admin.5.in
server/admin.c

index 3ea15b117401f848c27bddc7529e2d9973633fe1..9fd8a1d7f308ce20f96b6f6782728d1fce0dd152 100644 (file)
@@ -257,6 +257,10 @@ Emits an
 line reporting the IP address and port number stored for
 .IR peer .
 .SP
 line reporting the IP address and port number stored for
 .IR peer .
 .SP
+.BI "BGCANCEL " tag
+Cancels the background job with the named
+.IR tag .
+.SP
 .BI "CHECKCHAL " challenge
 Verifies a challenge as being one earlier issued by
 .B GETCHAL
 .BI "CHECKCHAL " challenge
 Verifies a challenge as being one earlier issued by
 .B GETCHAL
@@ -311,6 +315,11 @@ packets which are to be encrypted and sent to
 Used by configuration scripts so that they can set up routing tables
 appropriately after adding new peers.
 .SP
 Used by configuration scripts so that they can set up routing tables
 appropriately after adding new peers.
 .SP
+.B "JOBS"
+Emits an
+.B INFO
+line giving the tag for each outstanding background job.
+.SP
 .BI "KILL " peer
 Causes the server to forget all about
 .IR peer .
 .BI "KILL " peer
 Causes the server to forget all about
 .IR peer .
@@ -646,6 +655,11 @@ The DNS name
 .I hostname
 took too long to resolve.
 .SP
 .I hostname
 took too long to resolve.
 .SP
+.BI "tag-exists " tag
+(For long-running commands.)  The named
+.I tag
+is already the tag of an outstanding job.
+.SP
 .BI "unknown-command " token
 The command
 .B token
 .BI "unknown-command " token
 The command
 .B token
@@ -669,6 +683,14 @@ The service name
 .I service
 couldn't be found in 
 .BR /etc/services .
 .I service
 couldn't be found in 
 .BR /etc/services .
+.TP
+.BI "unknown-tag " tag
+(For
+.BR BGCANCEL .)
+The given
+.I tag
+is not the tag for any outstanding background job.  It may have just
+finished.
 .SH "NOTIFICATIONS"
 .\"* 30 Notification broadcasts (NOTE codes)
 The following notifications are sent to clients who request them.
 .SH "NOTIFICATIONS"
 .\"* 30 Notification broadcasts (NOTE codes)
 The following notifications are sent to clients who request them.
index 1660106c42b27e370b499f445409569f272b04c1..927f3ca4fa5085772bc55696ea78b4f4a80bf557 100644 (file)
@@ -620,6 +620,25 @@ static peer *a_findpeer(admin *a, const char *pn)
 #define BGTAG(bg)                                                      \
   (((admin_bgop *)(bg))->tag ? ((admin_bgop *)(bg))->tag : "<foreground>")
 
 #define BGTAG(bg)                                                      \
   (((admin_bgop *)(bg))->tag ? ((admin_bgop *)(bg))->tag : "<foreground>")
 
+/* --- @a_bgfind@ --- *
+ *
+ * Arguments:  @admin *a@ = a client block
+ *             @const char *tag@ = the requested tag
+ *
+ * Returns:    The requested background job, or null.
+ */
+
+static admin_bgop *a_bgfind(admin *a, const char *tag)
+{
+  admin_bgop *bg;
+
+  for (bg = a->bg; bg; bg = bg->next) {
+    if (bg->tag && strcmp(tag, bg->tag) == 0)
+      return (bg);
+  }
+  return (0);
+}
+
 /* --- @a_bgrelease@ --- *
  *
  * Arguments:  @admin_bgop *bg@ = backgrounded operation
 /* --- @a_bgrelease@ --- *
  *
  * Arguments:  @admin_bgop *bg@ = backgrounded operation
@@ -681,16 +700,21 @@ static void a_bgfail(admin_bgop *bg, const char *fmt, ...)
  *             @const char *tag@ = background tag, or null for foreground
  *             @void (*cancel)(admin_bgop *)@ = cancel function
  *
  *             @const char *tag@ = background tag, or null for foreground
  *             @void (*cancel)(admin_bgop *)@ = cancel function
  *
- * Returns:    ---
+ * Returns:    Zero for success, nonzero on failure.
  *
  * Use:                Links a background job into the list.
  */
 
  *
  * Use:                Links a background job into the list.
  */
 
-static void a_bgadd(admin *a, admin_bgop *bg, const char *tag,
-                   void (*cancel)(admin_bgop *))
+static int a_bgadd(admin *a, admin_bgop *bg, const char *tag,
+                  void (*cancel)(admin_bgop *))
 {
 {
-  if (tag)
+  if (tag) {
+    if (a_bgfind(a, tag)) {
+      a_fail(a, "tag-exists", "%s", tag, A_END);
+      return (-1);
+    }
     bg->tag = xstrdup(tag);
     bg->tag = xstrdup(tag);
+  }
   else {
     bg->tag = 0;
     selbuf_disable(&a->b);
   else {
     bg->tag = 0;
     selbuf_disable(&a->b);
@@ -703,6 +727,7 @@ static void a_bgadd(admin *a, admin_bgop *bg, const char *tag,
   a->bg = bg;
   T( trace(T_ADMIN, "admin: add bgop %s", BGTAG(bg)); )
   if (tag) a_write(a, "DETACH", tag, A_END);
   a->bg = bg;
   T( trace(T_ADMIN, "admin: add bgop %s", BGTAG(bg)); )
   if (tag) a_write(a, "DETACH", tag, A_END);
+  return (0);
 }
 
 /*----- Name resolution operations ----------------------------------------*/
 }
 
 /*----- Name resolution operations ----------------------------------------*/
@@ -834,7 +859,8 @@ static void a_resolve(admin *a, admin_resop *r, const char *tag,
    * answer straight away.
    */
 
    * answer straight away.
    */
 
-  a_bgadd(a, &r->bg, tag, a_rescancel);
+  if (a_bgadd(a, &r->bg, tag, a_rescancel))
+    goto fail;
   T( trace(T_ADMIN, "admin: %u, resop %s, hostname `%s'",
           a->seq, BGTAG(r), r->addr); )
 
   T( trace(T_ADMIN, "admin: %u, resop %s, hostname `%s'",
           a->seq, BGTAG(r), r->addr); )
 
@@ -1086,7 +1112,8 @@ static void a_ping(admin *a, unsigned ac, char *av[],
     return;
   pg = xmalloc(sizeof(*pg));
   gettimeofday(&pg->pingtime, 0);
     return;
   pg = xmalloc(sizeof(*pg));
   gettimeofday(&pg->pingtime, 0);
-  a_bgadd(a, &pg->bg, tag, a_pingcancel);
+  if (a_bgadd(a, &pg->bg, tag, a_pingcancel))
+    goto fail;
   T( trace(T_ADMIN, "admin: ping op %s: %s to %s",
           BGTAG(pg), cmd, p_name(p)); )
   if (p_pingsend(p, &pg->ping, msg, t, a_pong, pg)) {
   T( trace(T_ADMIN, "admin: ping op %s: %s to %s",
           BGTAG(pg), cmd, p_name(p)); )
   if (p_pingsend(p, &pg->ping, msg, t, a_pong, pg)) {
@@ -1098,6 +1125,7 @@ static void a_ping(admin *a, unsigned ac, char *av[],
 bad_syntax:
   a_fail(a, "bad-syntax", "%s", cmd, "[OPTIONS] PEER", cmd, A_END);
 fail:
 bad_syntax:
   a_fail(a, "bad-syntax", "%s", cmd, "[OPTIONS] PEER", cmd, A_END);
 fail:
+  if (pg) xfree(pg);
   return;
 }
 
   return;
 }
 
@@ -1225,6 +1253,30 @@ static void acmd_daemon(admin *a, unsigned ac, char *av[])
   }
 }
 
   }
 }
 
+static void acmd_jobs(admin *a, unsigned ac, char *av[])
+{
+  admin_bgop *bg;
+
+  for (bg = a->bg; bg; bg = bg->next) {
+    assert(bg->tag);
+    a_info(a, "%s", bg->tag, A_END);
+  }
+  a_ok(a);
+}
+
+static void acmd_bgcancel(admin *a, unsigned ac, char *av[])
+{
+  admin_bgop *bg;
+
+  if ((bg = a_bgfind(a, av[0])) == 0)
+    a_fail(a, "unknown-tag", "%s", av[0], A_END);
+  else {
+    bg->cancel(bg);
+    a_bgrelease(bg);
+    a_ok(a);
+  }
+}
+
 static void acmd_list(admin *a, unsigned ac, char *av[])
 {
   peer *p;
 static void acmd_list(admin *a, unsigned ac, char *av[])
 {
   peer *p;
@@ -1414,6 +1466,7 @@ static void acmd_help(admin */*a*/, unsigned /*ac*/, char */*av*/[]);
 static const acmd acmdtab[] = {
   { "add",     "[OPTIONS] PEER ADDR ...", 2,   0xffff, acmd_add },
   { "addr",    "PEER",                 1,      1,      acmd_addr },
 static const acmd acmdtab[] = {
   { "add",     "[OPTIONS] PEER ADDR ...", 2,   0xffff, acmd_add },
   { "addr",    "PEER",                 1,      1,      acmd_addr },
+  { "bgcancel",        "TAG",                  1,      1,      acmd_bgcancel },
   { "checkchal", "CHAL",               1,      1,      acmd_checkchal },
   { "daemon",  0,                      0,      0,      acmd_daemon },
   { "eping",   "[OPTIONS] PEER",       1,      0xffff, acmd_eping },
   { "checkchal", "CHAL",               1,      1,      acmd_checkchal },
   { "daemon",  0,                      0,      0,      acmd_daemon },
   { "eping",   "[OPTIONS] PEER",       1,      0xffff, acmd_eping },
@@ -1422,6 +1475,7 @@ static const acmd acmdtab[] = {
   { "greet",   "PEER CHAL",            2,      2,      acmd_greet },
   { "help",    0,                      0,      0,      acmd_help },
   { "ifname",  "PEER",                 1,      1,      acmd_ifname },
   { "greet",   "PEER CHAL",            2,      2,      acmd_greet },
   { "help",    0,                      0,      0,      acmd_help },
   { "ifname",  "PEER",                 1,      1,      acmd_ifname },
+  { "jobs",    0,                      0,      0,      acmd_jobs },
   { "kill",    "PEER",                 1,      1,      acmd_kill },
   { "list",    0,                      0,      0,      acmd_list },
   { "notify",  "MESSAGE ...",          1,      0xffff, acmd_notify },
   { "kill",    "PEER",                 1,      1,      acmd_kill },
   { "list",    0,                      0,      0,      acmd_list },
   { "notify",  "MESSAGE ...",          1,      0xffff, acmd_notify },