diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-02-25 16:17:36 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-02-25 16:17:36 +0200 |
commit | c9abb69acae95a0136ee1b03dec8b08d9639005e (patch) | |
tree | fa5849647e6d9430289a71035630475a82f4cf54 /src | |
parent | 1ec50721c1aa5959009f0c74afc8b7796f4ffd20 (diff) | |
download | pies-c9abb69acae95a0136ee1b03dec8b08d9639005e.tar.gz pies-c9abb69acae95a0136ee1b03dec8b08d9639005e.tar.bz2 |
Implement "telinit environ" ctl command
* src/ctl.c: New endpoint "environ"
* src/pies.h (sysvinit_envlocate)
(sysvinit_envdelete)
(sysvinit_envupdate): New protos.
* src/piesctl.c: New subcommand "telinit environ".
* src/sysvinit.c (sysvinit_envlocate)
(sysvinit_envdelete)
(sysvinit_envupdate): New functions.
(sysvinit_begin): Create allocated copies of
instance and pies_master_argv to avoid them being
rewritten by calls to mf_proctitle_format
Diffstat (limited to 'src')
-rw-r--r-- | src/acl.c | 2 | ||||
-rw-r--r-- | src/ctl.c | 86 | ||||
-rw-r--r-- | src/pies.h | 4 | ||||
-rw-r--r-- | src/piesctl.c | 143 | ||||
-rw-r--r-- | src/sysvinit.c | 90 |
5 files changed, 293 insertions, 32 deletions
@@ -150,3 +150,3 @@ _parse_token (struct acl_entry *entry, const grecs_value_t *value) || strcmp (value->v.string, "any") == 0) - /* FIXME: Nothing? */ ; + /* nothing */ ; else if (strcmp (value->v.string, "auth") == 0 @@ -487,2 +487,3 @@ json_error_reply_create (const char *msg) val = json_reply_create (); + json_object_set_string (val, "status", "ER"); json_object_set_string (val, "error_message", "%s", msg); @@ -922,2 +923,4 @@ static void res_runlevel (struct ctlio *, enum http_method, char const *, struct json_value *); +static void res_environ (struct ctlio *, enum http_method, char const *, + struct json_value *); static void res_conf (struct ctlio *, enum http_method, char const *, @@ -944,2 +947,3 @@ static struct ctlio_resource restab[] = { { S(/runlevel), CTL_ADMIN_STATE, pred_sysvinit, res_runlevel }, + { S(/environ), CTL_ADMIN_STATE, pred_sysvinit, res_environ }, { NULL } @@ -2405 +2409,83 @@ res_conf (struct ctlio *io, enum http_method meth, } + +/* GET /environ - List entire environment + * ["RUNLEVEL=3", "CONSOLE=/dev/tty", ...] + * GET /environ/NAME - Get value of variable NAME + * { "status":"OK", "value":"..." } + * { "status":"ER", "error_message":"..." } + * DELETE /environ/NAME - Unset variable + * { "status":"OK" } + * { "status":"ER", "error_message":"..." } + * PUT /environ/NAME=VALUE - Set variable + * { "status":"OK" } + * { "status":"ER", "error_message":"..." } + */ +static void +env_reply (struct ctlio *io, int ok, int rc) +{ + switch (rc) + { + case 0: + io->code = ok; + io->output.reply = json_reply_create (); + json_object_set_string (io->output.reply, "status", "OK"); + break; + + case 1: + ctlio_reply (io, 403, NULL); + break; + + case -1: + ctlio_reply (io, 404, NULL); + } +} + +static void +res_environ (struct ctlio *io, enum http_method meth, + char const *uri, struct json_value *json) +{ + if (meth == METH_GET) + { + if (uri && uri[1]) + { + char *value; + + if (sysvinit_envlocate (uri + 1, &value) == -1) + ctlio_reply (io, 404, NULL); + else + { + env_reply (io, 200, 0); + json_object_set_string (io->output.reply, "value", "%s", value); + } + } + else + { + size_t i; + + io->output.reply = json_new_array (); + io->code = 200; + for (i = 0; sysvinit_environ_hint[i]; i++) + { + json_array_append (io->output.reply, + json_new_string (sysvinit_environ_hint[i])); + } + } + } + else if (meth == METH_DELETE) + { + if (!(uri && uri[0])) + ctlio_reply (io, 400, NULL); + else + env_reply (io, 200, sysvinit_envupdate (uri + 1)); + } + else if (meth == METH_PUT) + { + if (!(uri && uri[0])) + ctlio_reply (io, 400, NULL); + else + env_reply (io, 201, sysvinit_envupdate (uri + 1)); + } + else + ctlio_reply (io, 405, NULL); + +} @@ -548,2 +548,6 @@ void sysvinit_parse_argv (int argc, char **argv); +int sysvinit_envlocate (char const *name, char **value); +int sysvinit_envdelete (char const *name); +int sysvinit_envupdate (char const *var); + extern char *sysvinit_environ_hint[]; diff --git a/src/piesctl.c b/src/piesctl.c index ad0981b..eecb6f6 100644 --- a/src/piesctl.c +++ b/src/piesctl.c @@ -892,3 +892,3 @@ shttp_fatal (struct shttp_connection *conn) } - + static void @@ -1039,3 +1039,3 @@ shttp_getval (struct shttp_connection *conn, char const *name, default: - grecs_error (NULL, errno, _("can't get value of \"%s\""), name); + grecs_error (NULL, errno, _("can't get value of \"%s\""), name); } @@ -1770,3 +1770,5 @@ com_reboot (struct cmdline_parser_state *state) <telinit> ::= "telinit" <initcmd> - <initcmd> ::= "runlevel" | "runlevel" <level> + <initcmd> ::= <runlevel> | <environ> + <runlevel> ::= "runlevel" | "runlevel" <level> + <environ> ::= "environ" "list" [<NAME>] | "environ" "set" <NAME>"="<VALUE> */ @@ -1811,2 +1813,3 @@ telinit_parse_runlevel (struct telinit_parser *p) + p->uri = "/runlevel"; if (!tok) @@ -1824,3 +1827,115 @@ telinit_parse_runlevel (struct telinit_parser *p) } - + +static void +telinit_format_environ (struct shttp_connection *conn) +{ + int err = 0; + + switch (conn->result->type) + { + case json_arr: + { + size_t i, n; + + n = json_array_size (conn->result); + for (i = 0; i < n; i++) + { + struct json_value *v; + json_array_get (conn->result, i, &v); + printf ("%s\n", v->v.s); + } + } + break; + + case json_object: + { + struct json_value *val; + + val = json_object_require_type (conn->result, "status", json_string); + if (strcmp (val->v.s, "OK") == 0) + { + if (json_object_get_type (conn->result, "value", + json_string, &val) == 0) + printf ("%s\n", val->v.s); + } + else if (strcmp (val->v.s, "ER") == 0) + { + if (json_object_get_type (conn->result, "error_message", + json_string, &val) == 0) + fputs (val->v.s, stderr); + else + { + grecs_error (NULL, 0, "%s", _("unknown error")); + err = 1; + } + } + else + { + grecs_error (NULL, 0, "%s", _("unrecognized response")); + err = 1; + } + } + break; + + default: + grecs_error (NULL, 0, "unexpected response type"); + err = 1; + } + if (err) + print_json (stderr, conn->result); +} + +static void +telinit_format_modenv (struct shttp_connection *conn) +{ + /* Nothing */ +} + +static void +telinit_list_environ (struct telinit_parser *p) +{ + char const *tok = next_token (p->state); + assert_eol (p->state); + p->method = METH_GET; + p->format = telinit_format_environ; + if (tok) + { + size_t n = 0; + grecs_asprintf (&p->uri, &n, "/environ/%s", tok); + } + else + p->uri = "/environ"; +} + +static void +telinit_mod_environ (struct telinit_parser *p, int set) +{ + char const *tok = next_token (p->state); + assert_eol (p->state); + p->method = set ? METH_PUT : METH_DELETE; + p->format = telinit_format_modenv; + if (tok) + { + size_t n = 0; + grecs_asprintf (&p->uri, &n, "/environ/%s", tok); + } + else + p->uri = "/environ"; +} + +static void +telinit_parse_environ (struct telinit_parser *p) +{ + char const *tok = require_token (p->state); + + if (strcmp (tok, "list") == 0) + telinit_list_environ (p); + else if (strcmp (tok, "set") == 0) + telinit_mod_environ (p, 1); + else if (strcmp (tok, "unset") == 0) + telinit_mod_environ (p, 0); + else + parse_error (_("expected \"list\" or \"set\", but found \"%s\""), tok); +} + static void @@ -1832,2 +1947,4 @@ telinit_parse (struct telinit_parser *parser) telinit_parse_runlevel (parser); + if (strcmp (tok, "environ") == 0) + telinit_parse_environ (parser); else @@ -1845,2 +1962,3 @@ com_telinit (struct cmdline_parser_state *state) parser.query = NULL; + parser.uri = NULL; telinit_parse (&parser); @@ -1851,2 +1969,3 @@ com_telinit (struct cmdline_parser_state *state) case METH_GET: + case METH_DELETE: break; @@ -1877,4 +1996,4 @@ com_telinit (struct cmdline_parser_state *state) - shttp_process (conn, parser.method, "/runlevel"); - if (conn->resp.code == 200 && !dump && parser.format) + shttp_process (conn, parser.method, parser.uri); + if (conn->resp.code / 100 == 2 && !dump && parser.format) parser.format (conn); @@ -2196,3 +2315,4 @@ static struct comtab comtab[] = { N_("add FILE of given SYNTAX to the list of configuration files"), NULL }, - { NULL, "file del[ete] NAME [NAME...]", + /* TRANSLATORS: Translate only words in upper case */ + { NULL, N_("file del[ete] NAME [NAME...]"), N_("remove listed names from the list of configuration files"), NULL }, @@ -2203,2 +2323,11 @@ static struct comtab comtab[] = { com_telinit }, + /* TRANSLATORS: Translate only words in upper case */ + { NULL, N_("environ list [NAME]"), + N_("list init execution environment"), NULL }, + /* TRANSLATORS: Translate only words in upper case */ + { NULL, N_("environ set NAME=VALUE"), + N_("update execution environment"), NULL }, + /* TRANSLATORS: Translate only words in upper case */ + { NULL, N_("environ unset NAME"), + N_("update execution environment"), NULL }, { NULL } diff --git a/src/sysvinit.c b/src/sysvinit.c index 0b12b4a..695dc5c 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -391,2 +391,53 @@ envsetup (void) } + +int +sysvinit_envlocate (char const *name, char **value) +{ + int i, j; + char *var; + + for (i = 0; (var = sysvinit_environ_hint[i]); i++) + { + for (j = 0; var[j] && name[j] == var[j]; j++) + ; + if (!name[j] && var[j] == '=') + { + if (value) + *value = var + j + 1; + return i; + } + } + return -1; +} + +int +sysvinit_envupdate (char const *var) +{ + int i, j; + size_t len; + + len = strcspn (var, "="); + for (i = 0; i < NR_ENVHINT; i++) + { + char *s = sysvinit_environ_hint[i]; + if (s) + { + for (j = 0; *s && j < len; j++, s++) + if (var[j] != *s) break; + if (*s != '=' || j != len) + continue; + if (i < ENVI_AVAIL) + return 1; + free (sysvinit_environ_hint[i]); + } + + if (var[len] == '=') + sysvinit_environ_hint[i] = grecs_strdup (var); + else + while ((sysvinit_environ_hint[i] = sysvinit_environ_hint[i+1])) + ++i; + return 0; + } + return -1; +} @@ -395,4 +446,2 @@ sysvinit_setenv (char const *data, int size) { - int i, j; - while (size) @@ -405,24 +454,3 @@ sysvinit_setenv (char const *data, int size) data += len; - if (strncmp (var, "INIT_", 5) != 0) - continue; - len = strcspn (var, "="); - for (i = ENVI_AVAIL; i < NR_ENVHINT; i++) - { - char *s = sysvinit_environ_hint[i]; - if (s) - { - for (j = 0; *s && j < len; j++, s++) - if (var[j] != *s) break; - if (*s != '=' || j != len) - continue; - free (sysvinit_environ_hint[i]); - } - - if (var[len] == '=') - sysvinit_environ_hint[i] = grecs_strdup (var); - else - for (j = i + 1; j < NR_ENVHINT; j++, i++) - sysvinit_environ_hint[i] = sysvinit_environ_hint[j]; - break; - } + sysvinit_envupdate (var); } @@ -737,2 +765,15 @@ sysvinit_realloc (void *ptr, size_t size) +static void +save_argv (void) +{ + int i; + char **av; + instance = grecs_strdup (instance); + av = grecs_calloc (pies_master_argc + 1, sizeof (av[0])); + for (i = 0; i < pies_master_argc; i++) + av[i] = grecs_strdup (pies_master_argv[i]); + av[i] = NULL; + pies_master_argv = av; +} + void @@ -759,2 +800,3 @@ sysvinit_begin (void) sysvinit_sysdep_begin (); + save_argv (); if (emergency) |