aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
@@ -145,13 +145,13 @@ create_acl_sockaddr (int family, int len)
static int
_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;
else
return 1;
return 0;
diff --git a/src/ctl.c b/src/ctl.c
index 61ed55e..731b31b 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -482,12 +482,13 @@ json_object_set_bool (struct json_value *obj, char const *name, int val)
static struct json_value *
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;
}
struct ctlio
{
@@ -917,12 +918,14 @@ method_decode (char const *method)
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 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 *);
static int pred_sysvinit (void);
struct ctlio_resource
@@ -939,12 +942,13 @@ static struct ctlio_resource restab[] = {
#define S(s) #s, (sizeof (#s)-1)
{ S(/instance), CTL_ADMIN_STATE, NULL, res_instance },
{ S(/conf), CTL_ADMIN_STATE, NULL, res_conf },
{ 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
};
static struct ctlio_resource *
find_resource (struct ctlio *io, const char *endpoint)
@@ -2400,6 +2404,88 @@ res_conf (struct ctlio *io, enum http_method meth,
ctlio_reply (io, 405, NULL);
}
}
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
@@ -543,12 +543,16 @@ void sysvinit_sysdep_begin (void);
void sysvinit_power (void);
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;
#ifndef INIT_FIFO
# define INIT_FIFO "/dev/initctl"
#endif
diff --git a/src/piesctl.c b/src/piesctl.c
index ad0981b..eecb6f6 100644
--- a/src/piesctl.c
+++ b/src/piesctl.c
@@ -887,13 +887,13 @@ shttp_fatal (struct shttp_connection *conn)
else
status = EX_UNAVAILABLE;
}
exit (status);
}
-
+
static void
echo_off (struct termios *stored_settings)
{
struct termios new_settings;
tcgetattr (0, stored_settings);
new_settings = *stored_settings;
@@ -1034,13 +1034,13 @@ shttp_getval (struct shttp_connection *conn, char const *name,
case 1:
grecs_error (NULL, 0, _("no \"%s\" member"), 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;
}
struct kwtrans
{
@@ -1765,13 +1765,15 @@ com_reboot (struct cmdline_parser_state *state)
shttp_io_init (&state->conn->req);
shttp_process (state->conn, METH_PUT, "/instance/PID");
}
/*
<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
{
struct cmdline_parser_state *state;
int method;
struct json_value *query;
@@ -1806,12 +1808,13 @@ telinit_format_runlevel (struct shttp_connection *conn)
static void
telinit_parse_runlevel (struct telinit_parser *p)
{
char const *tok = next_token (p->state);
+ p->uri = "/runlevel";
if (!tok)
{
p->method = METH_GET;
p->format = telinit_format_runlevel;
}
else
@@ -1819,20 +1822,134 @@ telinit_parse_runlevel (struct telinit_parser *p)
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_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)
{
char const *tok = require_token (parser->state);
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);
}
static void
com_telinit (struct cmdline_parser_state *state)
@@ -1840,18 +1957,20 @@ com_telinit (struct cmdline_parser_state *state)
struct shttp_connection *conn = state->conn;
struct telinit_parser parser;
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:
{
struct grecs_txtacc *acc = grecs_txtacc_create ();;
struct json_format fmt = {
@@ -1872,14 +1991,14 @@ com_telinit (struct cmdline_parser_state *state)
default:
parse_error ("%s", _("bad syntax"));
}
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);
}
/*
* piesctl config reload
* piesctl config file clear
@@ -2191,19 +2310,29 @@ static struct comtab comtab[] = {
N_("reload configuration"), com_config },
{ NULL, "file clear",
N_("clear configuration file list"), NULL },
/* 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 }
};
static int
comtabend (struct comtab *p)
{
diff --git a/src/sysvinit.c b/src/sysvinit.c
index 0b12b4a..695dc5c 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -386,48 +386,76 @@ envsetup (void)
logmsg (LOG_ERR, "console device name too long");
else
strcpy (str + sizeof (ENVAR_CONSOLE) - 1, console_device);
}
}
}
+
+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;
size_t len = strlen (var) + 1;
size -= len;
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);
}
}
int
sysvinit_set_runlevel (int newlevel)
{
@@ -732,12 +760,25 @@ sysvinit_realloc (void *ptr, size_t size)
logmsg (LOG_ERR, _("out of memory"));
unintr_sleep (5);
}
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)
{
int sigv[] = {
SIGINT,
SIGPWR,
@@ -754,12 +795,13 @@ sysvinit_begin (void)
console_stty ();
setsid ();
envsetup ();
sysvinit_runlevel_setup (PIES_COMP_DEFAULT);
add_extra_sigv (sigv, ARRAY_SIZE (sigv));
sysvinit_sysdep_begin ();
+ save_argv ();
if (emergency)
start_shell (emergency_shell);
}
#define IS_RUNNING_DISABLED_PROG(prog) \
(IS_COMPONENT (prog) \

Return to:

Send suggestions and report system problems to the System administrator.