diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2016-01-02 23:58:06 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-01-02 23:58:06 +0200 |
commit | 6db017a32e379bb2eb7878771dea969f77c3168c (patch) | |
tree | 0e1563b8239f7c681708c64c0d693f6541e4e155 | |
parent | 061afaf6385340f87bbeaa6d7e8ff6befa532551 (diff) | |
download | pies-6db017a32e379bb2eb7878771dea969f77c3168c.tar.gz pies-6db017a32e379bb2eb7878771dea969f77c3168c.tar.bz2 |
Switch to new control interface.
Old control options (--status, --restart-components) rewritten using
piesctl.
SIGUSR1 and SIGUSR2 no longer handled.
* lib/arraymember.c (array_index): New function.
* lib/libpies.h: Likewise.
* src/cmdline.opt: Fix copyright years.
* src/piesctl-cl.opt: Likewise.
* src/ctl.c (ctlio_do_command): Implement restart.
(pies_control_url): New function.
(eval_env): rename json to result.
New member cond.
Restore pcond_ functions.
(json_to_pcond): New function.
(res_programs): Conditional selection of programs to list.
Implement restart.
* src/pies.c (ctlfile, statfile): Remove.
(pies_keywords): Mark control-file and stat-file as inactive.
(default_sigv): Remove SIGUSR1 and SIGUSR2
(pies_check_status): Don't send SIGUSR2.
(stop_components): Remove.
(request_restart_components): Rewrite as a wrapper.
Call piesctl to do the job.
(list_components): New function.
* src/pies.h (ACTION_COMPRELOAD)
(ACTION_DUMPSTATS): Remove. All callers changed.
(progman_dump_stats): Remove.
* src/piesctl.c (shttp_request_send): Don't initialize conn->req; the
caller is responsible for that.
(parse_condition, json_to_string)
(parse_condition_to_uri): New functions.
(com_list): Read conditional expression from the command line.
(com_restart): Implement.
* src/progman.c (progman_dump_stats): Remove.
-rw-r--r-- | lib/arraymember.c | 17 | ||||
-rw-r--r-- | lib/libpies.h | 3 | ||||
-rw-r--r-- | src/cmdline.opt | 4 | ||||
-rw-r--r-- | src/ctl.c | 442 | ||||
-rw-r--r-- | src/pies.c | 161 | ||||
-rw-r--r-- | src/pies.h | 6 | ||||
-rw-r--r-- | src/piesctl-cl.opt | 2 | ||||
-rw-r--r-- | src/piesctl.c | 247 | ||||
-rw-r--r-- | src/progman.c | 136 |
9 files changed, 703 insertions, 315 deletions
diff --git a/lib/arraymember.c b/lib/arraymember.c index 14ace99..010f4a1 100644 --- a/lib/arraymember.c +++ b/lib/arraymember.c @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. - Copyright (C) 2007, 2008, 2009, 2010, 2013 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 @@ -21,7 +21,7 @@ #include "libpies.h" int -is_array_member (char * const * ar, char const *str) +is_array_member (char * const *ar, char const *str) { for (; *ar; ++ar) { @@ -31,3 +31,16 @@ is_array_member (char * const * ar, char const *str) return 0; } +int +array_index (char * const *ar, char const *str) +{ + int i; + + for (i = 0; ar[i]; i++) + { + if (strcmp (ar[i], str) == 0) + return i; + } + return -1; +} + diff --git a/lib/libpies.h b/lib/libpies.h index dab36df..b04182e 100644 --- a/lib/libpies.h +++ b/lib/libpies.h @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. - Copyright (C) 2009, 2010, 2011, 2013, 2015 Sergey Poznyakoff + Copyright (C) 2009-2011, 2013, 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 @@ -51,6 +51,7 @@ int strtotok_ci (struct tokendef *tab, const char *str, int *pres); int toktostr (struct tokendef *tab, int tok, const char **pres); int is_array_member (char * const * ar, char const *str); +int array_index (char * const *ar, char const *str); int strsplit3 (const char *input, char *result[3], int flag); /* url.c */ diff --git a/src/cmdline.opt b/src/cmdline.opt index 18791b6..e425518 100644 --- a/src/cmdline.opt +++ b/src/cmdline.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 @@ -18,7 +18,7 @@ OPTIONS_BEGIN("pies", [<process invocation and execution supervisor>], [<>], [<gnu>], - [<copyright_year=2008-2014>], + [<copyright_year=2008-2016>], [<copyright_holder=Sergey Poznyakoff>]) GROUP(Operation Mode) @@ -1000,8 +1000,20 @@ ctlio_do_command (struct ctlio *io, struct wordsplit *uri) //FIXME: Reply json } } + else if (method != METH_POST + && uri->ws_wordc > 1 + && strchr ("\"{[", uri->ws_wordv[uri->ws_wordc-1][0])) + { + json = json_parse_string (uri->ws_wordv[uri->ws_wordc-1], + strlen (uri->ws_wordv[uri->ws_wordc-1])); + if (!json) + ctlio_reply (io, 400, NULL); + free (uri->ws_wordv[uri->ws_wordc-1]); + uri->ws_wordv[uri->ws_wordc-1] = NULL; + uri->ws_wordc--; + } else - json = json_value_create (json_null); + json = json_new_bool (1); res->handler (io, method, uri->ws_wordc, uri->ws_wordv, json); json_value_free (json); @@ -1138,11 +1150,9 @@ ctl_accept (int socket, void *data) return 0; } -void -ctl_open () +char const * +pies_control_url (void) { - int fd; - if (!control.url) { char *str = xasprintf (DEFAULT_CONTROL_URL, instance); @@ -1150,11 +1160,19 @@ ctl_open () { logmsg (LOG_CRIT, _("%s: cannot create URL: %s"), str, strerror (errno)); - return; + exit (EX_OSERR); } free (str); } - + return control.url->string; +} + +void +ctl_open () +{ + int fd; + + pies_control_url (); fd = create_socket (control.url, SOCK_STREAM, NULL, 077); if (fd == -1) { @@ -1271,7 +1289,8 @@ res_instance (struct ctlio *io, enum http_method meth, struct eval_env { struct ctlio *io; - struct json_value *json; + struct pcond_node *cond; + struct json_value *result; }; static int @@ -1299,26 +1318,14 @@ auth_prog (struct prog *prog, struct ctlio *io) } return 0; } - -static struct json_value *prog_serialize (struct prog *prog); - -static int -selector (struct prog *prog, void *data) -{ - struct eval_env *env = data; - - if (auth_prog (prog, env->io)) - json_array_append (env->json, prog_serialize (prog)); - return 0; -} -static char const *pies_type_str[] = { +static char * const pies_type_str[] = { [TYPE_COMPONENT] = "component", [TYPE_REDIRECTOR] = "redirector", [TYPE_COMMAND] = "command" }; -static char const *pies_comp_mode_str[] = { +static char * const pies_comp_mode_str[] = { [pies_comp_exec] = "exec", [pies_comp_accept] = "accept", [pies_comp_inetd] = "inetd", @@ -1337,7 +1344,7 @@ static char const *pies_comp_mode_str[] = { [pies_comp_kbrequest] = "kbrequest" }; -static char const *status_str[] = { +static char * const pies_status_str[] = { [status_enabled] = "enabled", [status_disabled] = "disabled", [status_listener] = "listener", @@ -1348,7 +1355,7 @@ static char const *status_str[] = { static void format_idx (struct json_value *obj, const char *name, unsigned i, - char const **a, size_t s) + char * const *a, size_t s) { if (i < s && a[i]) json_object_set (obj, name, json_new_string (a[i])); @@ -1356,7 +1363,318 @@ format_idx (struct json_value *obj, const char *name, unsigned i, #define FORMAT_IDX(io,n,a,i) \ format_idx (io, n, i, a, sizeof(a)/sizeof(a[0])) + +enum pcond_type + { + pcond_true, + pcond_component, + pcond_type, + pcond_mode, + pcond_status, + pcond_not, + pcond_and, + pcond_or + }; + +struct pcond_node +{ + enum pcond_type type; + union + { + char *tag; + enum pies_comp_mode mode; + enum prog_status status; + enum prog_type type; + struct pcond_node *unary; + struct pcond_node *binary[2]; + } v; +}; + +static struct pcond_node * +pcond_node_alloc (enum pcond_type t) +{ + struct pcond_node *pn; + + pn = grecs_zalloc (sizeof (*pn)); + pn->type = t; + return pn; +} + +static void +pcond_node_free (struct pcond_node *node) +{ + if (!node) + return; + switch (node->type) + { + case pcond_not: + pcond_node_free (node->v.unary); + break; + + case pcond_and: + case pcond_or: + pcond_node_free (node->v.binary[0]); + pcond_node_free (node->v.binary[1]); + break; + + default: + break; + } + grecs_free (node); +} + +static int +pcond_eval (struct pcond_node *node, struct prog *p) +{ + if (!node) + return 0; + switch (node->type) + { + case pcond_true: + return 1; + + case pcond_component: + return strcmp (p->tag, node->v.tag) == 0; + + case pcond_type: + return p->type == node->v.type; + + case pcond_mode: + return IS_COMPONENT (p) && p->v.p.comp->mode == node->v.mode; + + case pcond_status: + return IS_COMPONENT (p) && p->v.p.status == node->v.status; + + case pcond_not: + return !pcond_eval (node->v.unary, p); + + case pcond_and: + if (!pcond_eval (node->v.binary[0], p)) + return 0; + return pcond_eval (node->v.binary[1], p); + + case pcond_or: + if (pcond_eval (node->v.binary[0], p)) + return 1; + return pcond_eval (node->v.binary[1], p); + + default: + abort (); + } +} + +static int json_to_pcond (struct ctlio *io, struct json_value *val, + struct pcond_node **pnode); + +static int +pcond_conv_component (struct pcond_node *node, struct json_value *arg, + struct ctlio *io) +{ + if (arg->type != json_string) + { + ctlio_reply (io, 400, "component must be string"); + return -1; + } + node->v.tag = arg->v.s; + return 0; +} + +static int +pcond_conv_n (struct pcond_node *node, struct json_value *arg, + struct ctlio *io, char * const *ar, const char *what) +{ + int n; + + if (arg->type != json_string) + { + ctlio_reply (io, 400, "%s must be string", what); + return -1; + } + n = array_index (ar, arg->v.s); + if (n == -1) + { + ctlio_reply (io, 400, "bad %s", what); + return -1; + } + return n; +} + +static int +pcond_conv_type (struct pcond_node *node, struct json_value *arg, + struct ctlio *io) +{ + int n = pcond_conv_n (node, arg, io, pies_type_str, "type"); + if (n == -1) + return -1; + node->v.type = n; + return 0; +} + +static int +pcond_conv_mode (struct pcond_node *node, struct json_value *arg, + struct ctlio *io) +{ + int n = pcond_conv_n (node, arg, io, pies_type_str, "mode"); + if (n == -1) + return -1; + node->v.mode = n; + return 0; +} + +static int +pcond_conv_status (struct pcond_node *node, struct json_value *arg, + struct ctlio *io) +{ + int n = pcond_conv_n (node, arg, io, pies_status_str, "status"); + if (n == -1) + return -1; + node->v.status = n; + return 0; +} +static int +pcond_conv_not (struct pcond_node *node, struct json_value *arg, + struct ctlio *io) +{ + return json_to_pcond (io, arg, &node->v.unary); +} + +static int +pcond_conv_binary (struct pcond_node *node, struct json_value *arg, + struct ctlio *io) +{ + struct json_value *v; + + if (arg->type != json_arr) + { + ctlio_reply (io, 400, "arguments to binary opcode must be array"); + return -1; + } + json_array_get (arg, 0, &v); + if (json_to_pcond (io, v, &node->v.binary[0])) + return -1; + json_array_get (arg, 1, &v); + if (json_to_pcond (io, v, &node->v.binary[1])) + return -1; + return 0; +} + +struct pcond_conv { + char *term; + int (*handler) (struct pcond_node *, struct json_value *arg, struct ctlio *); +}; + +static struct pcond_conv pcond_conv[] = { + [pcond_true] = { "true", NULL }, + [pcond_component] = { "component", pcond_conv_component }, + [pcond_type] = { "type", pcond_conv_type }, + [pcond_mode] = { "mode", pcond_conv_mode }, + [pcond_status] = { "status", pcond_conv_status }, + [pcond_not] = { "not", pcond_conv_not }, + [pcond_and] = { "and", pcond_conv_binary }, + [pcond_or] = { "or", pcond_conv_binary }, +}; + +static int max_type = sizeof (pcond_conv) / sizeof (pcond_conv[0]); + +static int +pcond_conv_find (char const *name) +{ + int i; + for (i = 0; i < max_type; i++) + { + if (strcmp (pcond_conv[i].term, name) == 0) + return i; + } + return -1; +} + +static int +object_to_cond (struct ctlio *io, struct json_value *obj, + struct pcond_node **pnode) +{ + struct json_value *op, *arg; + struct pcond_node *node; + int type; + + if (json_object_get (obj, "op", &op)) + { + ctlio_reply (io, 400, "bad conditional: missing op"); + return -1; + } + if (json_object_get (obj, "arg", &arg)) + { + ctlio_reply (io, 400, "bad conditional: missing arg"); + return -1; + } + + if (op->type != json_string) + { + ctlio_reply (io, 400, "bad conditional: bad op type"); + return -1; + } + + type = pcond_conv_find (op->v.s); + if (type == -1) + { + ctlio_reply (io, 400, "bad conditional: unknown opcode"); + return -1; + } + + node = pcond_node_alloc (type); + if (pcond_conv[type].handler && pcond_conv[type].handler (node, arg, io)) + { + pcond_node_free (node); + return -1; + } + *pnode = node; + return 0; +} + +static int +json_to_pcond (struct ctlio *io, struct json_value *val, + struct pcond_node **pnode) +{ + if (!val) + *pnode = pcond_node_alloc (pcond_true); + else + switch (val->type) + { + case json_null: + *pnode = NULL; + break; + + case json_bool: + if (val->v.b) + *pnode = pcond_node_alloc (pcond_true); + else + *pnode = NULL; + break; + + case json_number: + case json_string: + case json_arr: + ctlio_reply (io, 400, "bad conditional"); + return -1; + + case json_object: + return object_to_cond (io, val, pnode); + } + return 0; +} + +static struct json_value *prog_serialize (struct prog *prog); + +static int +selector (struct prog *prog, void *data) +{ + struct eval_env *env = data; + + if (auth_prog (prog, env->io) && pcond_eval (env->cond, prog)) + json_array_append (env->result, prog_serialize (prog)); + return 0; +} + static struct json_value * prog_serialize (struct prog *prog) { @@ -1370,7 +1688,7 @@ prog_serialize (struct prog *prog) { case TYPE_COMPONENT: FORMAT_IDX (ret, "mode", pies_comp_mode_str, prog->v.p.comp->mode); - FORMAT_IDX (ret, "status", status_str, prog->v.p.status); + FORMAT_IDX (ret, "status", pies_status_str, prog->v.p.status); if (prog->pid) json_object_set_number (ret, "PID", prog->pid); @@ -1402,6 +1720,33 @@ prog_serialize (struct prog *prog) } static void +component_stop (struct ctlio *io, struct prog *prog) +{ + if (prog->v.p.comp->flags & CF_DISABLED) + ctlio_reply (io, 409, "already stopped"); + else + { + progman_stop_component (prog); + prog->v.p.comp->flags |= CF_DISABLED; + ctlio_reply (io, 200, "Component stopped"); + } +} + +static void +component_start (struct ctlio *io, struct prog *prog) +{ + if (!(prog->v.p.comp->flags & CF_DISABLED)) + ctlio_reply (io, 409, "already running"); + else + { + prog->v.p.comp->flags &= ~CF_DISABLED; + prog->v.p.status = status_enabled; + kill (getpid (), SIGALRM); + ctlio_reply (io, 200, "Component started"); + } +} + +static void res_programs (struct ctlio *io, enum http_method meth, size_t pathc, char **pathv, struct json_value *json) @@ -1411,9 +1756,12 @@ res_programs (struct ctlio *io, enum http_method meth, struct eval_env env; env.io = io; - env.json = json_new_array (); + if (json_to_pcond (io, json, &env.cond)) + return; + env.result = json_new_array (); progman_foreach (selector, &env); - io->output.reply = env.json; + pcond_node_free (env.cond); + io->output.reply = env.result; io->code = 200; } else if (meth == METH_DELETE || meth == METH_PUT) @@ -1431,32 +1779,38 @@ res_programs (struct ctlio *io, enum http_method meth, ctlio_reply (io, 404, "Not a component"); else if (meth == METH_DELETE) { - if (prog->v.p.comp->flags & CF_DISABLED) - ctlio_reply (io, 409, "already stopped"); - else - { - progman_stop_component (prog); - prog->v.p.comp->flags |= CF_DISABLED; - ctlio_reply (io, 200, "Component stopped"); - } + component_stop (io, prog); } else { - if (!(prog->v.p.comp->flags & CF_DISABLED)) - ctlio_reply (io, 409, "already running"); - else - { - prog->v.p.comp->flags &= ~CF_DISABLED; - prog->v.p.status = status_enabled; - kill (getpid (), SIGALRM); - ctlio_reply (io, 200, "Component started"); - } + component_start (io, prog); } } else ctlio_reply (io, 403, NULL); } } + else if (meth == METH_POST) + { + if (json->type != json_arr) + { + ctlio_reply (io, 400, NULL); + } + else + { + size_t i, n; + + n = json_array_size (json); + for (i = 0; i < n; i++) + { + struct json_value *v; + if (json_array_get (json, i, &v) == 0 && v->type == json_string) + progman_stop_tag (v->v.s); + } + kill (getpid (), SIGALRM); + } + ctlio_reply (io, 200, "Done"); + } else ctlio_reply (io, 405, NULL); } @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. - Copyright (C) 2008-2011, 2013-2015 Sergey Poznyakoff + Copyright (C) 2008-2011, 2013-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 @@ -45,8 +45,6 @@ enum pies_command command; char *statedir = DEFAULT_STATE_DIR; char *instance; char *pidfile; -char *ctlfile; -char *statfile; char *qotdfile; int inetd_mode; mode_t pies_umask = 0; @@ -1581,16 +1579,16 @@ struct grecs_keyword pies_keywords[] = { }, {"control-file", NULL, - N_("Set location of the control file."), - grecs_type_string, GRECS_DFLT, - &ctlfile, 0, + N_("Ignored for compatibility with version 1.2."), + grecs_type_string, GRECS_DFLT|GRECS_INAC, + NULL, 0, NULL, }, {"stat-file", NULL, - N_("Set location of the statistics output file."), - grecs_type_string, GRECS_DFLT, - &statfile, 0, + N_("Ignored for compatibility with version 1.2."), + grecs_type_string, GRECS_DFLT|GRECS_INAC, + NULL, 0, NULL, }, {"qotd-file", @@ -1802,14 +1800,6 @@ sig_handler (int sig) case SIGALRM: got_alarm = 1; break; - - case SIGUSR1: - action = ACTION_COMPRELOAD; - break; - - case SIGUSR2: - action = ACTION_DUMPSTATS; - break; } } @@ -1839,8 +1829,6 @@ static int default_sigv[] = { SIGINT, SIGHUP, SIGALRM, - SIGUSR1, - SIGUSR2, SIGPIPE }; @@ -1924,86 +1912,49 @@ enum pies_status pies_check_status (pid_t *ppid) { pid_t pid = pidfile_read (0); - int i; - int rc; if (pid <= 0) return pies_status_ctr; *ppid = pid; - if (kill (pid, SIGUSR2)) + if (kill (pid, 0)) return pies_status_stale; - for (i = 0; i < 4 && (rc = access (statfile, R_OK)); i++) - sleep (1); - - if (rc) - return pies_status_noresp; return pies_status_running; } - void -stop_components () +request_restart_components (size_t cc, char **cv) { - FILE *fp; - size_t size = 0; - char *buf = NULL; - - logmsg (LOG_INFO, _("stopping components")); - - fp = fopen (ctlfile, "r"); - if (!fp) - { - logmsg (LOG_ERR, _("cannot open control file `%s': %s"), - ctlfile, strerror (errno)); - return; - } - if (unlink (ctlfile)) - { - logmsg (LOG_ERR, _("cannot unlink control file `%s': %s"), - ctlfile, strerror (errno)); - fclose (fp); - return; - } - - while (getline (&buf, &size, fp) > 0) - { - size_t len = strlen (buf); - if (len == 0) - continue; - if (buf[len - 1] == '\n') - buf[len - 1] = 0; - progman_stop_tag (buf); - } - - free (buf); - fclose (fp); + char **argv; + size_t i; + + argv = xcalloc (cc + 4, sizeof (*argv)); + argv[0] = "piesctl"; + argv[1] = "--url"; + argv[2] = (char*) pies_control_url (); + for (i = 0; i < cc; i++) + argv[3 + i] = cv[i]; + argv[3 + i] = NULL; + execv (argv[0], argv); + logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno)); + exit (EX_OSFILE); } -int -request_restart_components (char **argv) +void +list_components (void) { - FILE *fp; - pid_t pid = pidfile_read (1);//FIXME: useless in init mode, init has pid == 1 - - if (pid == -1) - return 1; - - fp = fopen (ctlfile, "w"); - if (!fp) - { - logmsg (LOG_ERR, _("cannot open control file `%s': %s"), - ctlfile, strerror (errno)); - return 1; - } - for (; *argv; argv++) - fprintf (fp, "%s\n", *argv); - fclose (fp); - - kill (pid, SIGUSR1); - return 0; + char *argv[5]; + + argv[0] = "piesctl"; + argv[1] = "--url"; + argv[2] = (char*) pies_control_url (); + argv[3] = "list"; + argv[4] = NULL; + execv (argv[0], argv); + logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno)); + exit (EX_OSFILE); } @@ -2026,11 +1977,7 @@ int pies_status () { pid_t pid; - FILE *fp; - if (unlink (statfile) && errno != ENOENT) - logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"), - statfile, strerror (errno)); switch (pies_check_status (&pid)) { case pies_status_ctr: @@ -2047,27 +1994,11 @@ pies_status () logmsg (LOG_INFO, _("pies seems to run with pid %lu, but is not responding"), (unsigned long) pid); - if (unlink (statfile)) - logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"), - statfile, strerror (errno)); return 2; case pies_status_running: - fp = fopen (statfile, "r"); - if (!fp) - logmsg (LOG_ERR, _("cannot open statfile `%s': %s"), - statfile, strerror (errno)); - else - { - char c; - - if (unlink (statfile)) - logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"), - statfile, strerror (errno)); - while ((c = fgetc (fp)) != EOF) - fputc (c, stdout); - fclose (fp); - } + list_components (); + break; } return 0; } @@ -2188,10 +2119,6 @@ set_state_file_names (const char *base) { if (!pidfile) pidfile = mkfilename (statedir, base, ".pid"); - if (!ctlfile) - ctlfile = mkfilename (statedir, base, ".ctl"); - if (!statfile) - statfile = mkfilename (statedir, base, ".stat"); if (!qotdfile) qotdfile = mkfilename (statedir, base, ".qotd"); } @@ -2366,8 +2293,8 @@ main (int argc, char **argv) pies_priv_setup (&pies_privs); if (pies_umask) umask (pies_umask); - exit (request_restart_components (argv + index)); - + request_restart_components (argc - index, argv + index); + case COM_RELOAD: exit (pies_reload ()); @@ -2458,18 +2385,6 @@ main (int argc, char **argv) pies_pause (); switch (action) { - case ACTION_COMPRELOAD: - stop_components (); - progman_cleanup (0); - progman_start (); - action = ACTION_CONT; - break; - - case ACTION_DUMPSTATS: - progman_dump_stats (statfile); - action = ACTION_CONT; - break; - case ACTION_STOP: case ACTION_RESTART: if (init_process) @@ -1,5 +1,5 @@ /* This file is part of GNU Pies. - Copyright (C) 2008, 2009, 2010, 2011, 2013-2015 Sergey Poznyakoff + Copyright (C) 2008-2011, 2013-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 @@ -267,8 +267,6 @@ enum pies_action { ACTION_CONT, ACTION_STOP, ACTION_RESTART, - ACTION_COMPRELOAD, - ACTION_DUMPSTATS, ACTION_CTRLALTDEL, ACTION_KBREQUEST }; @@ -317,7 +315,6 @@ void progman_cleanup (int expect_term); void progman_filter (int (*filter) (struct component *, void *data), void *data); void progman_stop_tag (const char *name); -void progman_dump_stats (const char *filename); void progman_dump_prereq (void); void progman_dump_depmap (void); int progman_accept (int socket, void *data); @@ -541,3 +538,4 @@ struct control extern struct control control; void ctl_open(void); +char const *pies_control_url (void); diff --git a/src/piesctl-cl.opt b/src/piesctl-cl.opt index a83616e..d026269 100644 --- a/src/piesctl-cl.opt +++ b/src/piesctl-cl.opt @@ -18,7 +18,7 @@ OPTIONS_BEGIN("piesctl", [<GNU pies control program>], [<COMMAND [ARG...]>], [<gnu>], - [<copyright_year=2008-2015>], + [<copyright_year=2008-2016>], [<copyright_holder=Sergey Poznyakoff>]) OPTION(instance,i,NAME, diff --git a/src/piesctl.c b/src/piesctl.c index 9c5ef8b..626463c 100644 --- a/src/piesctl.c +++ b/src/piesctl.c @@ -622,7 +622,6 @@ send_header (void *sym, void *data) static void shttp_request_send (struct shttp_connection *conn, int method, char const *uri) { - shttp_io_init (&conn->req); shttp_send_line (conn, "%s %s %s", method_names[method], uri, http_version); shttp_send_line (conn, "Host: %s", conn->url->host ? conn->url->host : "localhost"); @@ -1160,10 +1159,229 @@ print_comp (FILE *fp, struct json_value *v, size_t n) fputc ('\n', fp); } +struct pcond_parser_state +{ + int argc; + char **argv; +}; + +static char * +next_token (struct pcond_parser_state *state) +{ + if (state->argc == 0) + return NULL; + --state->argc; + return *state->argv++; +} + +static char const * +peek_token (struct pcond_parser_state *state) +{ + if (state->argc == 0) + return NULL; + return *state->argv; +} + +static struct json_value * +json_new_array2 (struct json_value *a, struct json_value *b) +{ + struct json_value *ret = json_new_array (); + json_array_append (ret, a); + json_array_append (ret, b); + return ret; +} + +static struct json_value * +json_encode_op (char const *op, struct json_value *arg) +{ + struct json_value *ret = json_new_object (); + json_object_set (ret, "op", json_new_string (op)); + json_object_set (ret, "arg", arg); + return ret; +} + +static void pcond_parse_or (struct pcond_parser_state *, struct json_value **); + +static void +pcond_parse_unary (struct pcond_parser_state *state, struct json_value **ret) +{ + char const *term = next_token (state); + + if (!term) + *ret = json_new_bool (1); + else + { + static char *arg_terms[] = { + "type", "mode", "status", "component", NULL + }; + + if (strcasecmp (term, "all") == 0) + *ret = json_new_bool (1); + else if (is_array_member (arg_terms, term)) + { + if (!peek_token (state)) + { + grecs_error (NULL, 0, _("%s requires argument"), term); + exit (EX_USAGE); + } + *ret = json_encode_op (term, json_new_string (next_token (state))); + } + else if (strcasecmp (term, "not") == 0) + { + struct json_value *val; + if (!peek_token (state)) + { + grecs_error (NULL, 0, _("%s requires argument"), term); + exit (EX_USAGE); + } + pcond_parse_unary (state, &val); + *ret = json_encode_op (term, val); + } + else if (term[0] == '(') + { + pcond_parse_or (state, ret); + term = next_token (state); + if (!term || term[0] != ')') + { + grecs_error (NULL, 0, _("unbalanced parentesis")); + exit (EX_USAGE); + } + } + else + { + grecs_error (NULL, 0, _("parse error at %s"), term); + exit (EX_USAGE); + } + } +} + +static void +pcond_parse_and (struct pcond_parser_state *state, struct json_value **ret) +{ + char const *token; + struct json_value *left, *right; + + pcond_parse_unary (state, &left); + token = peek_token (state); + if (!token || strcmp (token, "and")) + { + *ret = left; + return; + } + next_token (state); + pcond_parse_and (state, &right); + *ret = json_encode_op (token, json_new_array2 (left, right)); +} + +static void +pcond_parse_or (struct pcond_parser_state *state, struct json_value **ret) +{ + char const *token; + struct json_value *left, *right; + + pcond_parse_and (state, &left); + token = peek_token (state); + if (!token || strcmp (token, "or")) + { + *ret = left; + return; + } + next_token (state); + pcond_parse_or (state, &right); + *ret = json_encode_op (token, json_new_array2 (left, right)); +} + +static struct json_value * +parse_condition (int argc, char **argv) +{ + struct json_value *val = NULL; + + if (argc > 1) + { + struct pcond_parser_state state; + state.argc = argc - 1; + state.argv = argv + 1; + pcond_parse_or (&state, &val); + if (state.argc) + { + grecs_error (NULL, 0, + _("expected end of statement, but found \"%s\""), + *state.argv); + exit (EX_USAGE); + } +#if 0 + print_json (stdout, val); + exit (0); +#endif + } + return val; +} + +static void +acc_writer (void *closure, char const *text, size_t len) +{ + grecs_txtacc_grow ((struct grecs_txtacc *)closure, text, len); +} + +static char * +json_to_string (struct json_value *val) +{ + struct grecs_txtacc *acc = grecs_txtacc_create (); + struct json_format fmt = { + .indent = 0, + .precision = 0, + .write = acc_writer, + .data = acc + }; + char *ret; + + json_format_value (val, &fmt); + grecs_txtacc_grow_char (acc, 0); + ret = grecs_txtacc_finish (acc, 1); + grecs_txtacc_free (acc); |