aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-02-13 12:48:59 +0200
committerSergey Poznyakoff <gray@gnu.org>2016-02-13 12:48:59 +0200
commit3c774556e22cd30c42304614e14218a767e4d700 (patch)
treecdcc278f470b2ef8863cf10655315f8579f679b2 /src
parent92145d8331e824a54109c53032f0ca4b2df71f5f (diff)
downloadpies-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.c64
-rw-r--r--src/pies.h9
-rw-r--r--src/piesctl.c136
-rw-r--r--src/sysvinit.c58
4 files changed, 243 insertions, 24 deletions
diff --git a/src/ctl.c b/src/ctl.c
index bc2f78d..6f50246 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -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);
+}
+
diff --git a/src/pies.h b/src/pies.h
index 1b77398..9fb87c6 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -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);
+}

Return to:

Send suggestions and report system problems to the System administrator.