New commands BGCANCEL (cancel an outstanding job) and JOBS (list
outstanding jobs).
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
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 .
.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
.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.
#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
* @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: 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 (a_bgfind(a, tag)) {
+ a_fail(a, "tag-exists", "%s", tag, A_END);
+ return (-1);
+ }
else {
bg->tag = 0;
selbuf_disable(&a->b);
else {
bg->tag = 0;
selbuf_disable(&a->b);
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);
}
/*----- Name resolution operations ----------------------------------------*/
}
/*----- Name resolution operations ----------------------------------------*/
* 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); )
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)) {
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:
+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;
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 },
{ "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 },