+static void a_canceljob(admin_bgop *bg)
+{
+ admin_svcop *svc = (admin_svcop *)bg;
+
+ a_write(svc->prov, "SVCCANCEL", 0, "%s", a_jobidencode(svc), A_END);
+ a_jobdestroy(svc);
+}
+
+static void acmd_svcsubmit(admin *a, unsigned ac, char *av[])
+{
+ const char *tag = 0;
+ admin_service *svc;
+ admin_svcop *svcop;
+ const char *ver = 0;
+ dstr d = DSTR_INIT;
+
+ OPTIONS(ac, av, {
+ OPTARG("-background", arg, { tag = arg; })
+ OPTARG("-version", arg, { ver = arg; })
+ });
+ if (!*av) goto bad_syntax;
+ if ((svc = a_svcfind(a, *av)) == 0) goto fail;
+ if (ver && versioncmp(svc->version, ver) < 0) {
+ a_fail(a, "service-too-old",
+ "%s", SYM_NAME(svc),
+ "%s", svc->version,
+ A_END);
+ goto fail;
+ }
+ if ((svcop = a_jobcreate(svc->prov)) == 0) {
+ a_fail(a, "provider-overloaded", A_END);
+ goto fail;
+ }
+ if (a_bgadd(a, &svcop->bg, tag, a_canceljob)) {
+ a_jobdestroy(svcop);
+ goto fail;
+ }
+ a_write(svc->prov, "SVCJOB", 0,
+ "%s", a_jobidencode(svcop),
+ "?TOKENS", av,
+ A_END);
+ goto done;
+
+bad_syntax:
+ a_fail(a, "bad-syntax", "svcsubmit", "[OPTIONS] SERVICE ARGS...", A_END);
+fail:
+done:
+ dstr_destroy(&d);
+ return;
+}
+
+static void a_replycmd(admin *a, const char *status, int donep, char *av[])
+{
+ admin_svcop *svc;
+
+ if ((svc = a_jobiddecode(&a->j, av[0])) == 0) {
+ a_fail(a, "unknown-jobid", av[0], A_END);
+ return;
+ }
+ a_write(svc->bg.a, status, svc->bg.tag, "?TOKENS", av + 1, A_END);
+ if (donep) {
+ a_jobdestroy(svc);
+ a_bgrelease(&svc->bg);
+ }
+ a_ok(a);
+}
+
+static void acmd_svcok(admin *a, unsigned ac, char *av[])
+ { a_replycmd(a, "OK", 1, av); }
+static void acmd_svcinfo(admin *a, unsigned ac, char *av[])
+ { a_replycmd(a, "INFO", 0, av); }
+static void acmd_svcfail(admin *a, unsigned ac, char *av[])
+ { a_replycmd(a, "FAIL", 1, av); }
+