aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-02-25 16:17:36 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2016-02-25 16:17:36 +0200
commitc9abb69acae95a0136ee1b03dec8b08d9639005e (patch)
treefa5849647e6d9430289a71035630475a82f4cf54 /src
parent1ec50721c1aa5959009f0c74afc8b7796f4ffd20 (diff)
downloadpies-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.c2
-rw-r--r--src/ctl.c86
-rw-r--r--src/pies.h4
-rw-r--r--src/piesctl.c143
-rw-r--r--src/sysvinit.c90
5 files changed, 293 insertions, 32 deletions
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> ::= "telinit" <initcmd>
- <initcmd> ::= "runlevel" | "runlevel" <level>
+ <initcmd> ::= <runlevel> | <environ>
+ <runlevel> ::= "runlevel" | "runlevel" <level>
+ <environ> ::= "environ" "list" [<NAME>] | "environ" "set" <NAME>"="<VALUE>
*/
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);
}

Return to:

Send suggestions and report system problems to the System administrator.