From c9abb69acae95a0136ee1b03dec8b08d9639005e Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 25 Feb 2016 16:17:36 +0200 Subject: 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 --- src/acl.c | 2 +- src/ctl.c | 86 ++++++++++++++++++++++++++++++++++ src/pies.h | 4 ++ src/piesctl.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/sysvinit.c | 90 ++++++++++++++++++++++++++---------- 5 files changed, 293 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/acl.c b/src/acl.c index 7b834c9..7d7b110 100644 --- a/src/acl.c +++ b/src/acl.c @@ -148,7 +148,7 @@ _parse_token (struct acl_entry *entry, const grecs_value_t *value) { if (strcmp (value->v.string, "all") == 0 || strcmp (value->v.string, "any") == 0) - /* FIXME: Nothing? */ ; + /* nothing */ ; else if (strcmp (value->v.string, "auth") == 0 || strcmp (value->v.string, "authenticated") == 0) entry->authenticated = 1; diff --git a/src/ctl.c b/src/ctl.c index 61ed55e..731b31b 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -485,6 +485,7 @@ json_error_reply_create (const char *msg) struct json_value *val; val = json_reply_create (); + json_object_set_string (val, "status", "ER"); json_object_set_string (val, "error_message", "%s", msg); return val; } @@ -920,6 +921,8 @@ static void res_programs (struct ctlio *, enum http_method, char const *, struct json_value *); 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 *, struct json_value *); @@ -942,6 +945,7 @@ static struct ctlio_resource restab[] = { { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, NULL, res_programs }, { S(/runlevel), CTL_ADMIN_STATE, pred_sysvinit, res_runlevel }, + { S(/environ), CTL_ADMIN_STATE, pred_sysvinit, res_environ }, { NULL } #undef S }; @@ -2403,3 +2407,85 @@ res_conf (struct ctlio *io, enum http_method meth, else ctlio_reply (io, 404, NULL); } + +/* 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); + +} diff --git a/src/pies.h b/src/pies.h index c858932..6fce820 100644 --- a/src/pies.h +++ b/src/pies.h @@ -546,6 +546,10 @@ void sysvinit_report (struct json_value *obj); int sysvinit_set_runlevel (int newlevel); 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[]; extern char *init_fifo; diff --git a/src/piesctl.c b/src/piesctl.c index ad0981b..eecb6f6 100644 --- a/src/piesctl.c +++ b/src/piesctl.c @@ -890,7 +890,7 @@ shttp_fatal (struct shttp_connection *conn) exit (status); } - + static void echo_off (struct termios *stored_settings) { @@ -1037,7 +1037,7 @@ shttp_getval (struct shttp_connection *conn, char const *name, break; default: - grecs_error (NULL, errno, _("can't get value of \"%s\""), name); + grecs_error (NULL, errno, _("can't get value of \"%s\""), name); } return p; } @@ -1768,7 +1768,9 @@ com_reboot (struct cmdline_parser_state *state) /* ::= "telinit" - ::= "runlevel" | "runlevel" + ::= | + ::= "runlevel" | "runlevel" + ::= "environ" "list" [] | "environ" "set" "=" */ struct telinit_parser { @@ -1809,6 +1811,7 @@ telinit_parse_runlevel (struct telinit_parser *p) { char const *tok = next_token (p->state); + p->uri = "/runlevel"; if (!tok) { p->method = METH_GET; @@ -1822,7 +1825,119 @@ telinit_parse_runlevel (struct telinit_parser *p) p->format = NULL; } } - + +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 telinit_parse (struct telinit_parser *parser) { @@ -1830,6 +1945,8 @@ telinit_parse (struct telinit_parser *parser) if (strcmp (tok, "runlevel") == 0) telinit_parse_runlevel (parser); + if (strcmp (tok, "environ") == 0) + telinit_parse_environ (parser); else parse_error (_("unrecognized subcommand: %s"), tok); } @@ -1843,12 +1960,14 @@ com_telinit (struct cmdline_parser_state *state) parser.state = state; parser.method = METH_INVALID; parser.query = NULL; + parser.uri = NULL; telinit_parse (&parser); shttp_io_init (&conn->req); switch (parser.method) { case METH_GET: + case METH_DELETE: break; case METH_PUT: @@ -1875,8 +1994,8 @@ com_telinit (struct cmdline_parser_state *state) json_value_free (parser.query); - 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); } @@ -2194,13 +2313,23 @@ static struct comtab comtab[] = { /* TRANSLATORS: Translate only words in upper case */ { NULL, N_("file add SYNTAX FILE"), 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 }, { NULL, "file list", N_("list configuration files"), NULL }, { "telinit", "runlevel [N]", N_("list or change the runlevel"), 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 @@ -389,12 +389,61 @@ 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; +} static void sysvinit_setenv (char const *data, int size) { - int i, j; - while (size) { char const *var = data; @@ -403,28 +452,7 @@ sysvinit_setenv (char const *data, int size) if (size < 0) break; 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); } } @@ -735,6 +763,19 @@ sysvinit_realloc (void *ptr, size_t size) return p; } +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 sysvinit_begin (void) { @@ -757,6 +798,7 @@ sysvinit_begin (void) sysvinit_runlevel_setup (PIES_COMP_DEFAULT); add_extra_sigv (sigv, ARRAY_SIZE (sigv)); sysvinit_sysdep_begin (); + save_argv (); if (emergency) start_shell (emergency_shell); } -- cgit v1.2.1