From 061afaf6385340f87bbeaa6d7e8ff6befa532551 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 2 Jan 2016 11:18:28 +0200 Subject: piesctl: Implement all basic commands, except "restart" --- src/ctl.c | 4 +- src/piesctl-cl.opt | 8 +- src/piesctl.c | 338 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 336 insertions(+), 14 deletions(-) diff --git a/src/ctl.c b/src/ctl.c index ce13dab..cbc5fea 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. - Copyright (C) 2007-2013 Sergey Poznyakoff + Copyright (C) 2007-2016 Sergey Poznyakoff GNU Pies is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1446,7 +1446,7 @@ res_programs (struct ctlio *io, enum http_method meth, ctlio_reply (io, 409, "already running"); else { - prog->v.p.comp->flags &= CF_DISABLED; + prog->v.p.comp->flags &= ~CF_DISABLED; prog->v.p.status = status_enabled; kill (getpid (), SIGALRM); ctlio_reply (io, 200, "Component started"); diff --git a/src/piesctl-cl.opt b/src/piesctl-cl.opt index 04ff051..a83616e 100644 --- a/src/piesctl-cl.opt +++ b/src/piesctl-cl.opt @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. -*- c -*- - Copyright (C) 2008-2014 Sergey Poznyakoff + Copyright (C) 2008-2016 Sergey Poznyakoff GNU Pies is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -52,6 +52,12 @@ BEGIN ++verbose; END +OPTION(dump,d,, + []) +BEGIN + ++dump; +END + OPTION(url,u,URL, []) BEGIN diff --git a/src/piesctl.c b/src/piesctl.c index 0618caa..9c5ef8b 100644 --- a/src/piesctl.c +++ b/src/piesctl.c @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. - Copyright (C) 2015 Sergey Poznyakoff + Copyright (C) 2015, 2016 Sergey Poznyakoff GNU Pies is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ #include "progname.h" #include "libpies.h" #include "grecsasrt.h" +#include "fprintftime.h" struct pies_url *default_url; /* Control socket URL */ struct pies_url *url; @@ -43,6 +44,7 @@ char *config_file; char default_config_file[] = SYSCONFDIR "/piesctl.conf"; int preprocess_only; int verbose; +int dump; static void config_help (void); @@ -794,21 +796,29 @@ shttp_get_reply (struct shttp_connection *conn) } static void -stderr_writer (void *closure, char const *text, size_t len) +fp_writer (void *closure, char const *text, size_t len) { - fwrite (text, len, 1, stderr); + fwrite (text, len, 1, (FILE*) closure); } static void -shttp_format_result (struct shttp_connection *conn) +print_json (FILE *fp, struct json_value *v) { struct json_format fmt = { .indent = 2, .precision = 0, - .write = stderr_writer, + .write = fp_writer, + .data = fp }; + json_format_value (v, &fmt); + fputc ('\n', fp); +} + +static void +shttp_format_result (struct shttp_connection *conn, FILE *fp) +{ fprintf (stderr, "%s: raw JSON reply follows:\n", program_name); - json_format_value (conn->result, &fmt); + print_json (fp, conn->result); } static void @@ -821,7 +831,7 @@ shttp_fatal (struct shttp_connection *conn) if (jv->type == json_string) grecs_error (NULL, 0, "%s", jv->v.s); else - shttp_format_result (conn); + shttp_format_result (conn, stderr); } else grecs_error (NULL, 0, "%s", conn->status_line[2]); @@ -927,6 +937,8 @@ shttp_process (struct shttp_connection *conn, int method, char const *uri) { shttp_request_send (conn, method, uri); shttp_get_reply (conn); + if (dump && conn->result) + shttp_format_result (conn, stdout); if (conn->resp.code / 100 == 2) return; if (conn->resp.code == 401 && isatty (fileno (stdin))) @@ -936,24 +948,274 @@ shttp_process (struct shttp_connection *conn, int method, char const *uri) } } +static struct json_value * +shttp_getval (struct shttp_connection *conn, char const *name, + enum json_value_type type) +{ + struct json_value *p = NULL; + + switch (json_object_get (conn->result, name, &p)) + { + case 0: + if (p->type != type) + { + grecs_error (NULL, 0, _("\"%s\" has wrong type"), name); + p = NULL; + } + break; + + case 1: + grecs_error (NULL, 0, _("no \"%s\" member"), name); + break; + + default: + grecs_error (NULL, errno, _("can't get value of \"%s\""), name); + } + return p; +} + +struct kwtrans +{ + char const *name; + int c; +}; + +struct kwtrans mode_trans[] = { + { "exec", 'C' }, + { "accept", 'A' }, + { "inetd", 'I' }, + { "pass_fd", 'P' }, + { "wait", 'W' }, + { "once", 'c' }, + { "boot", 'B' }, + { "bootwait", 'w' }, + { "powerfail", 'F' }, + { "powerwait", 'f' }, + { "powerokwait", 'o' }, + { "ctrlaltdel", '3' }, + { "ondemand", 'D' }, + { "sysinit", 'i' }, + { "powerfailnow", 'n' }, + { "kbrequest", 'k' }, + { NULL } +}; + +struct kwtrans status_trans[] = { + { "enabled", 'R' }, + { "disabled", 'D' }, + { "listener", 'L' }, + { "sleeping", 's' }, + { "stopping", 'S' }, + { "finished", 'f' }, + { NULL } +}; + +static int +kwtoc (char const *s, struct kwtrans const *trans) +{ + for (; trans->name; trans++) + { + if (strcmp (trans->name, s) == 0) + return trans->c; + } + return '-'; +} + +static struct json_value * +getval (struct json_value *v, char const *name, enum json_value_type type, + int optional) +{ + struct json_value *p = NULL; + + switch (json_object_get (v, name, &p)) + { + case 0: + if (p->type != type) + { + grecs_error (NULL, 0, _("\"%s\" has wrong type"), name); + p = NULL; + } + break; + + case 1: + if (!optional) + grecs_error (NULL, 0, _("no \"%s\" member"), name); + break; + + default: + grecs_error (NULL, errno, _("can't get value of \"%s\""), name); + } + return p; +} + +static void +print_comp (FILE *fp, struct json_value *v, size_t n) +{ + struct json_value *p; + char const *type; + char fbuf[5]; + int fidx = 0; + int status = -1; + + if (v->type != json_object) + { + grecs_error (NULL, 0, _("%lu: unexpected value type"), + (unsigned long) n); + print_json (fp, v); + return; + } + + p = getval (v, "type", json_string, 0); + if (!p) + { + print_json (fp, v); + return; + } + type = p->v.s; + + p = getval (v, "tag", json_string, 0); + if (!p) + { + print_json (fp, v); + return; + } + + fprintf (fp, "%-16s ", p->v.s); + + if (strcmp (type, "component") == 0) + { + p = getval (v, "mode", json_string, 0); + if (v) + fbuf[fidx++] = kwtoc (p->v.s, mode_trans); + else + fbuf[fidx++] = '-'; + p = getval (v, "status", json_string, 0); + if (p) + fbuf[fidx++] = status = kwtoc (p->v.s, status_trans); + else + fbuf[fidx++] = '-'; + } + else if (strcmp (type, "redirector") == 0) + { + fbuf[fidx++] = 'R'; + } + else if (strcmp (type, "command") == 0) + { + fbuf[fidx++] = 'E'; + } + else + { + fbuf[fidx++] = '-'; + } + + fbuf[fidx++] = 0; + fprintf (fp, "%-8.8s ", fbuf); + + if (strcmp (type, "component") == 0) + { + p = getval (v, "PID", json_number, 1); + if (p) + fprintf (fp, "%10.0f ", p->v.n); + else if (status == 'L' /* listener */ + && (p = getval (v, "URL", json_string, 1))) + fprintf (fp, "%-10s ", p->v.s); + else + fprintf (fp, "%-10s ", "N/A"); + + if (status == 's') /* sleeping */ + { + p = getval (v, "wakeup-time", json_number, 0); + if (p) + { + time_t t = (time_t) p->v.n; + fprintftime (fp, "%H:%M:%S", localtime (&t), 0, 0); + } + } + + p = getval (v, "argv", json_arr, 0); + if (p) + { + size_t i, n = json_array_size (p); + + for (i = 0; i < n; i++) + { + struct json_value *elt; + if (json_array_get (p, i, &elt) == 0) + fprintf (fp, " %s", elt->v.s); + } + } + } + else if (strcmp (type, "redirector") == 0) + { + p = getval (v, "PID", json_number, 0); + if (p) + fprintf (fp, "%10.0f ", p->v.n); + } + else if (strcmp (type, "command") == 0) + { + p = getval (v, "command", json_string, 0); + if (p) + fprintf (fp, "%s", p->v.s); + } + fputc ('\n', fp); +} + static int com_list (struct shttp_connection *conn, int argc, char **argv) { shttp_process (conn, METH_GET, "/programs"); + if (!dump && conn->result && conn->result->type == json_arr) + { + size_t i, n = json_array_size (conn->result); + + for (i = 0; i < n; i++) + { + struct json_value *v; + + if (json_array_get (conn->result, i, &v) == 0) + print_comp (stdout, v, i); + } + } return 0; } static int com_stop (struct shttp_connection *conn, int argc, char **argv) { - abort (); + char *buf = NULL; + size_t len = 0; + size_t i; + + for (i = 1; i < argc; i++) + { + struct json_value *v; + grecs_asprintf (&buf, &len, "/programs/%s", argv[i]); + shttp_process (conn, METH_DELETE, buf); + v = shttp_getval (conn, "error_message", json_string); + if (v) + printf ("%s: %s\n", argv[i], v->v.s); + } + free (buf); return 0; } static int com_start (struct shttp_connection *conn, int argc, char **argv) { - abort (); + char *buf = NULL; + size_t len = 0; + size_t i; + + for (i = 1; i < argc; i++) + { + struct json_value *v; + grecs_asprintf (&buf, &len, "/programs/%s", argv[i]); + shttp_process (conn, METH_PUT, buf); + v = shttp_getval (conn, "error_message", json_string); + if (v) + printf ("%s: %s\n", argv[i], v->v.s); + } + free (buf); return 0; } @@ -964,17 +1226,65 @@ com_restart (struct shttp_connection *conn, int argc, char **argv) return 0; } +static int +com_id (struct shttp_connection *conn, int argc, char **argv) +{ + struct json_value *v; + + if (argc == 1) + { + size_t i; + static char *keywords[] = { + "package", + "version", + "instance", + "binary", + }; + + shttp_process (conn, METH_GET, "/instance"); + + for (i = 0; i < sizeof (keywords)/ sizeof (keywords[0]); i++) + { + v = shttp_getval (conn, keywords[i], json_string); + if (v) + printf ("%s: %s\n", keywords[i], v->v.s); + } + v = shttp_getval (conn, "PID", json_number); + if (v) + printf ("PID: %.0f\n", v->v.n); + } + else + { + char *buf = NULL; + size_t size = 0; + size_t i; + + for (i = 1; i < argc; i++) + { + grecs_asprintf (&buf, &size, "/instance/%s", argv[i]); + shttp_process (conn, METH_GET, buf); + if (json_object_get (conn->result, argv[i], &v) == 0) + { + printf ("%s: ", argv[i]); + print_json (stdout, v); + } + } + } + + return 0; +} + static int com_shutdown (struct shttp_connection *conn, int argc, char **argv) { - abort (); + shttp_process (conn, METH_DELETE, "/instance/PID"); return 0; } static int com_reboot (struct shttp_connection *conn, int argc, char **argv) { - abort (); + shttp_process (conn, METH_PUT, "/instance/PID"); return 0; } @@ -991,6 +1301,7 @@ static struct comtab comtab[] = { { "stop", com_stop }, { "start", com_start }, { "restart", com_restart }, + { "id", com_id }, { "shutdown", com_shutdown }, { "reboot", com_reboot }, { NULL } @@ -1052,6 +1363,11 @@ main (int argc, char **argv) parse_options (argc, argv, &i); argc -= i; argv += i; + if (argc == 0) + { + grecs_error (NULL, 0, _("not enough arguments")); + exit (EX_USAGE); + } parse_config (); -- cgit v1.2.1