diff options
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
@@ -18,7 +18,6 @@ #include "prog.h" #include "identity.h" #include "base64.h" -#include "json.h" struct control control; @@ -443,7 +442,7 @@ json_reply_create (void) return json_new_object (); } -static void +void json_object_set_string (struct json_value *obj, char const *name, char const *fmt, ...) { @@ -458,7 +457,7 @@ json_object_set_string (struct json_value *obj, grecs_free (s); } -static void +void json_object_set_number (struct json_value *obj, char const *name, double val) { json_object_set (obj, name, json_new_number (val)); @@ -904,21 +903,27 @@ static void res_instance (struct ctlio *, enum http_method, char const *, struct json_value *); 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); struct ctlio_resource { char const *uri; size_t uri_len; int states; + int (*predicate) (void); void (*handler) (struct ctlio *, enum http_method, char const *uri, struct json_value *); }; 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 } #undef S }; @@ -939,7 +944,8 @@ find_resource (struct ctlio *io, const char *endpoint) if (len >= p->uri_len && memcmp (p->uri, endpoint, p->uri_len) == 0 && (endpoint[p->uri_len] == 0 || endpoint[p->uri_len] == '/' - || endpoint[p->uri_len] == '?')) + || endpoint[p->uri_len] == '?') + && (!p->predicate || p->predicate())) return p; return NULL; } @@ -2010,3 +2016,49 @@ res_programs (struct ctlio *io, enum http_method meth, else res_programs_select (io, meth, uri, json); } + +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); +} + @@ -56,6 +56,7 @@ #include "identity.h" #include "acl.h" #include "libpies.h" +#include "json.h" #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) @@ -515,6 +516,9 @@ void sysvinit_runlevel_setup (int mask, int *wait); void sysvinit_sysdep_begin (void); void sysvinit_power (void); +void sysvinit_report (struct json_value *obj); +int sysvinit_set_runlevel (int newlevel); + extern char *sysvinit_environ_hint[]; extern char *init_fifo; @@ -578,3 +582,8 @@ struct control 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 @@ -1716,6 +1716,140 @@ com_reboot (struct shttp_connection *conn, int argc, char **argv) shttp_process (conn, METH_PUT, "/instance/PID"); } +/* + <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 **); struct comtab @@ -1736,6 +1870,8 @@ static struct comtab comtab[] = { com_id }, { "shutdown", NULL, N_("stop running pies instance"), com_shutdown }, { "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 @@ -425,6 +425,33 @@ 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; static void create_fifo (void); @@ -480,24 +507,7 @@ sysvinit_fifo_handler (int fd, void *data) break; 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); } break; @@ -1097,3 +1107,15 @@ powerfailcmd (int power_stat) sysvinit_runlevel_setup (mask, NULL); } + +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); +} |