diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2016-02-13 12:48:59 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-02-13 12:48:59 +0200 |
commit | 3c774556e22cd30c42304614e14218a767e4d700 (patch) | |
tree | cdcc278f470b2ef8863cf10655315f8579f679b2 /src | |
parent | 92145d8331e824a54109c53032f0ca4b2df71f5f (diff) | |
download | pies-3c774556e22cd30c42304614e14218a767e4d700.tar.gz pies-3c774556e22cd30c42304614e14218a767e4d700.tar.bz2 |
Implement on-demaind components; implement control socket telinit interface.
* src/pies.h: Include json.h
(sysvinit_report, sysvinit_set_runlevel)
(json_object_set_string, json_object_set_number): New protos.
* src/ctl.c (ctlio_resource)<predicate>: New member.
(restab): New endpoint: runlevel. Available only if run
as pid 1.
(find_resource): If predicate is not NULL, call it to
confirm that the endpoint is available.
* src/piesctl.c: New subcommand "telinit".
* src/sysvinit.c (sysvinit_set_runlevel): New function.
(sysvinit_fifo_handler): Implement on-demaind components.
Diffstat (limited to 'src')
-rw-r--r-- | src/ctl.c | 64 | ||||
-rw-r--r-- | src/pies.h | 9 | ||||
-rw-r--r-- | src/piesctl.c | 136 | ||||
-rw-r--r-- | src/sysvinit.c | 58 |
4 files changed, 243 insertions, 24 deletions
@@ -20,3 +20,2 @@ #include "base64.h" -#include "json.h" @@ -445,3 +444,3 @@ json_reply_create (void) -static void +void json_object_set_string (struct json_value *obj, @@ -460,3 +459,3 @@ json_object_set_string (struct json_value *obj, -static void +void json_object_set_number (struct json_value *obj, char const *name, double val) @@ -906,2 +905,6 @@ 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 int pred_sysvinit (void); @@ -912,2 +915,3 @@ struct ctlio_resource int states; + int (*predicate) (void); void (*handler) (struct ctlio *, enum http_method, @@ -918,5 +922,6 @@ static struct ctlio_resource restab[] = { #define S(s) #s, (sizeof (#s)-1) - { S(/instance), CTL_ADMIN_STATE, res_instance }, - { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, + { S(/instance), CTL_ADMIN_STATE, NULL, res_instance }, + { S(/programs), CTL_ADMIN_STATE|CTL_USER_STATE, NULL, res_programs }, + { S(/runlevel), CTL_ADMIN_STATE, pred_sysvinit, res_runlevel }, { NULL } @@ -941,3 +946,4 @@ find_resource (struct ctlio *io, const char *endpoint) || endpoint[p->uri_len] == '/' - || endpoint[p->uri_len] == '?')) + || endpoint[p->uri_len] == '?') + && (!p->predicate || p->predicate())) return p; @@ -2012 +2018,47 @@ res_programs (struct ctlio *io, enum http_method meth, } + +static int +pred_sysvinit (void) +{ + return init_process; +} + +static void +res_runlevel (struct ctlio *io, enum http_method meth, + char const *uri, struct json_value *json) +{ + if (uri) + ctlio_reply (io, 404, NULL); + else if (meth == METH_GET) + { + io->output.reply = json_reply_create (); + io->code = 200; + sysvinit_report (io->output.reply); + } + else if (meth == METH_PUT) + { + struct json_value *val; + // { "runlevel": "3" } + if (json_object_get (json, "runlevel", &val)) + ctlio_reply (io, 400, "missing runlevel request"); + else if (val->type != json_string) + ctlio_reply (io, 400, "bad runlevel type"); + else + { + io->output.reply = json_reply_create (); + io->code = 200; + if (strlen (val->v.s) == 1 + && sysvinit_set_runlevel (val->v.s[0]) == 0) + json_object_set_string (io->output.reply, "status", "OK"); + else + { + json_object_set_string (io->output.reply, "status", "ER"); + json_object_set_string (io->output.reply, "error_message", + "invalid runlevel value"); + } + } + } + else + ctlio_reply (io, 405, NULL); +} + @@ -58,2 +58,3 @@ #include "libpies.h" +#include "json.h" @@ -517,2 +518,5 @@ void sysvinit_power (void); +void sysvinit_report (struct json_value *obj); +int sysvinit_set_runlevel (int newlevel); + extern char *sysvinit_environ_hint[]; @@ -580 +584,6 @@ extern struct control control; int ctl_open(void); + +void json_object_set_string (struct json_value *obj, + char const *name, char const *fmt, ...); +void json_object_set_number (struct json_value *obj, + char const *name, double val); diff --git a/src/piesctl.c b/src/piesctl.c index f799ff4..d6a39a2 100644 --- a/src/piesctl.c +++ b/src/piesctl.c @@ -1718,2 +1718,136 @@ com_reboot (struct shttp_connection *conn, int argc, char **argv) +/* + <telinit> ::= "telinit" <initcmd> + <initcmd> ::= "runlevel" | "runlevel" <level> + */ +struct telinit_parser +{ + int argc; + char **argv; + int method; + struct json_value *query; + char *uri; + void (*format) (struct shttp_connection *); +}; + +static struct id_fmt runlevel_fmt[] = { + { "runlevel", json_string, id_fmt_string }, + { "prevlevel", json_string, id_fmt_string }, + { "bootstate", json_string, id_fmt_string }, + { "initdefault", json_string, id_fmt_string }, + { NULL } +}; + +static void +telinit_format_runlevel (struct shttp_connection *conn) +{ + struct id_fmt *fmt; + + for (fmt = runlevel_fmt; fmt->name; fmt++) + { + struct json_value *v = shttp_getval (conn, fmt->name, fmt->type); + if (v) + { + printf ("%s: ", fmt->name); + fmt->format (v); + putchar ('\n'); + } + } +} + +static char * +telinit_get_token (struct telinit_parser *p) +{ + if (p->argc == 0) + return NULL; + --p->argc; + return *p->argv++; +} + +static void +telinit_parse_runlevel (struct telinit_parser *p) +{ + char *tok = telinit_get_token (p); + + if (!tok) + { + p->method = METH_GET; + p->format = telinit_format_runlevel; + } + else + { + p->method = METH_PUT; + p->query = json_new_object (); + json_object_set (p->query, "runlevel", json_new_string (tok)); + p->format = NULL; + } +} + +static void +telinit_parse (struct telinit_parser *p) +{ + char *tok = telinit_get_token (p); + + if (strcmp (tok, "runlevel") == 0) + telinit_parse_runlevel (p); + else + { + grecs_error (NULL, 0, _("unrecognized subcommand: %s"), tok); + exit (EX_USAGE); + } +} + +static void +com_telinit (struct shttp_connection *conn, int argc, char **argv) +{ + struct telinit_parser parser; + + if (argc == 1) + { + grecs_error (NULL, 0, _("not enough arguments to telinit")); + exit (EX_USAGE); + } + + parser.argc = argc-1; + parser.argv = argv+1; + parser.method = METH_INVALID; + parser.query = NULL; + telinit_parse (&parser); + + shttp_io_init (&conn->req); + switch (parser.method) + { + case METH_GET: + break; + + case METH_PUT: + { + struct grecs_txtacc *acc = grecs_txtacc_create ();; + struct json_format fmt = { + .indent = 0, + .precision = 0, + .write = acc_writer, + .data = acc + }; + + json_format_value (parser.query, &fmt); + grecs_txtacc_grow_char (acc, 0); + conn->req.content = grecs_txtacc_finish (acc, 1); + conn->req.content_length = strlen (conn->req.content); + grecs_txtacc_free (acc); + } + break; + + default: + grecs_error (NULL, 0, _("bad syntax")); + exit (EX_USAGE); + } + + json_value_free (parser.query); + + shttp_process (conn, parser.method, "/runlevel"); + if (conn->resp.code == 200 && !dump && parser.format) + parser.format (conn); +} + typedef void (*ctlcom_t) (struct shttp_connection *, int, char **); @@ -1738,2 +1872,4 @@ static struct comtab comtab[] = { { "reboot", NULL, N_("restart pies instance"), com_reboot }, + { "telinit", "ARGS", N_("communicate with the init process"), + com_telinit }, { NULL } diff --git a/src/sysvinit.c b/src/sysvinit.c index 337b922..9e918c7 100644 --- a/src/sysvinit.c +++ b/src/sysvinit.c @@ -427,2 +427,29 @@ sysvinit_setenv (char const *data, int size) +int +sysvinit_set_runlevel (int newlevel) +{ + switch (newlevel) + { + case 'A': + case 'B': + case 'C': + sysvinit_demand (newlevel); + break; + + default: + if (newlevel == runlevel) + { + } + if (runlevel_index (newlevel) == -1) + return -1; + else + { + dfl_level = newlevel; + inittrans (); + } + } + return 0; +} + + char *init_fifo = INIT_FIFO; @@ -482,20 +509,3 @@ sysvinit_fifo_handler (int fd, void *data) default: - if (buf.req.runlevel != runlevel) - { - switch (buf.req.runlevel) - { - case 'A': - case 'B': - case 'C': - sysvinit_demand (buf.req.runlevel); - break; - - default: - if (runlevel_index (buf.req.runlevel) != -1) - { - dfl_level = buf.req.runlevel; - inittrans (); - } - } - } + sysvinit_set_runlevel (buf.req.runlevel); } @@ -1099 +1109,13 @@ powerfailcmd (int power_stat) } + +void +sysvinit_report (struct json_value *obj) +{ + json_object_set_string (obj, "runlevel", "%c", runlevel); + json_object_set_string (obj, "prevlevel", "%c", prevlevel); + json_object_set_string (obj, "bootstate", "%s", + boot_state_name[boot_state]); + if (initdefault) + json_object_set_string (obj, "initdefault", "%c", + initdefault); +} |