summaryrefslogtreecommitdiffabout
path: root/src/ctl.c
authorSergey Poznyakoff <gray@gnu.org>2016-01-02 21:58:06 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2016-01-02 21:58:06 (GMT)
commit6db017a32e379bb2eb7878771dea969f77c3168c (patch) (side-by-side diff)
tree0e1563b8239f7c681708c64c0d693f6541e4e155 /src/ctl.c
parent061afaf6385340f87bbeaa6d7e8ff6befa532551 (diff)
downloadpies-6db017a32e379bb2eb7878771dea969f77c3168c.tar.gz
pies-6db017a32e379bb2eb7878771dea969f77c3168c.tar.bz2
Switch to new control interface.
Old control options (--status, --restart-components) rewritten using piesctl. SIGUSR1 and SIGUSR2 no longer handled. * lib/arraymember.c (array_index): New function. * lib/libpies.h: Likewise. * src/cmdline.opt: Fix copyright years. * src/piesctl-cl.opt: Likewise. * src/ctl.c (ctlio_do_command): Implement restart. (pies_control_url): New function. (eval_env): rename json to result. New member cond. Restore pcond_ functions. (json_to_pcond): New function. (res_programs): Conditional selection of programs to list. Implement restart. * src/pies.c (ctlfile, statfile): Remove. (pies_keywords): Mark control-file and stat-file as inactive. (default_sigv): Remove SIGUSR1 and SIGUSR2 (pies_check_status): Don't send SIGUSR2. (stop_components): Remove. (request_restart_components): Rewrite as a wrapper. Call piesctl to do the job. (list_components): New function. * src/pies.h (ACTION_COMPRELOAD) (ACTION_DUMPSTATS): Remove. All callers changed. (progman_dump_stats): Remove. * src/piesctl.c (shttp_request_send): Don't initialize conn->req; the caller is responsible for that. (parse_condition, json_to_string) (parse_condition_to_uri): New functions. (com_list): Read conditional expression from the command line. (com_restart): Implement. * src/progman.c (progman_dump_stats): Remove.
Diffstat (limited to 'src/ctl.c') (more/less context) (ignore whitespace changes)
-rw-r--r--src/ctl.c442
1 files changed, 398 insertions, 44 deletions
diff --git a/src/ctl.c b/src/ctl.c
index cbc5fea..4f56923 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -1000,8 +1000,20 @@ ctlio_do_command (struct ctlio *io, struct wordsplit *uri)
//FIXME: Reply json
}
}
+ else if (method != METH_POST
+ && uri->ws_wordc > 1
+ && strchr ("\"{[", uri->ws_wordv[uri->ws_wordc-1][0]))
+ {
+ json = json_parse_string (uri->ws_wordv[uri->ws_wordc-1],
+ strlen (uri->ws_wordv[uri->ws_wordc-1]));
+ if (!json)
+ ctlio_reply (io, 400, NULL);
+ free (uri->ws_wordv[uri->ws_wordc-1]);
+ uri->ws_wordv[uri->ws_wordc-1] = NULL;
+ uri->ws_wordc--;
+ }
else
- json = json_value_create (json_null);
+ json = json_new_bool (1);
res->handler (io, method, uri->ws_wordc, uri->ws_wordv, json);
json_value_free (json);
@@ -1138,11 +1150,9 @@ ctl_accept (int socket, void *data)
return 0;
}
-void
-ctl_open ()
+char const *
+pies_control_url (void)
{
- int fd;
-
if (!control.url)
{
char *str = xasprintf (DEFAULT_CONTROL_URL, instance);
@@ -1150,11 +1160,19 @@ ctl_open ()
{
logmsg (LOG_CRIT, _("%s: cannot create URL: %s"),
str, strerror (errno));
- return;
+ exit (EX_OSERR);
}
free (str);
}
-
+ return control.url->string;
+}
+
+void
+ctl_open ()
+{
+ int fd;
+
+ pies_control_url ();
fd = create_socket (control.url, SOCK_STREAM, NULL, 077);
if (fd == -1)
{
@@ -1271,7 +1289,8 @@ res_instance (struct ctlio *io, enum http_method meth,
struct eval_env
{
struct ctlio *io;
- struct json_value *json;
+ struct pcond_node *cond;
+ struct json_value *result;
};
static int
@@ -1299,26 +1318,14 @@ auth_prog (struct prog *prog, struct ctlio *io)
}
return 0;
}
-
-static struct json_value *prog_serialize (struct prog *prog);
-
-static int
-selector (struct prog *prog, void *data)
-{
- struct eval_env *env = data;
-
- if (auth_prog (prog, env->io))
- json_array_append (env->json, prog_serialize (prog));
- return 0;
-}
-static char const *pies_type_str[] = {
+static char * const pies_type_str[] = {
[TYPE_COMPONENT] = "component",
[TYPE_REDIRECTOR] = "redirector",
[TYPE_COMMAND] = "command"
};
-static char const *pies_comp_mode_str[] = {
+static char * const pies_comp_mode_str[] = {
[pies_comp_exec] = "exec",
[pies_comp_accept] = "accept",
[pies_comp_inetd] = "inetd",
@@ -1337,7 +1344,7 @@ static char const *pies_comp_mode_str[] = {
[pies_comp_kbrequest] = "kbrequest"
};
-static char const *status_str[] = {
+static char * const pies_status_str[] = {
[status_enabled] = "enabled",
[status_disabled] = "disabled",
[status_listener] = "listener",
@@ -1348,7 +1355,7 @@ static char const *status_str[] = {
static void
format_idx (struct json_value *obj, const char *name, unsigned i,
- char const **a, size_t s)
+ char * const *a, size_t s)
{
if (i < s && a[i])
json_object_set (obj, name, json_new_string (a[i]));
@@ -1356,7 +1363,318 @@ format_idx (struct json_value *obj, const char *name, unsigned i,
#define FORMAT_IDX(io,n,a,i) \
format_idx (io, n, i, a, sizeof(a)/sizeof(a[0]))
+
+enum pcond_type
+ {
+ pcond_true,
+ pcond_component,
+ pcond_type,
+ pcond_mode,
+ pcond_status,
+ pcond_not,
+ pcond_and,
+ pcond_or
+ };
+
+struct pcond_node
+{
+ enum pcond_type type;
+ union
+ {
+ char *tag;
+ enum pies_comp_mode mode;
+ enum prog_status status;
+ enum prog_type type;
+ struct pcond_node *unary;
+ struct pcond_node *binary[2];
+ } v;
+};
+
+static struct pcond_node *
+pcond_node_alloc (enum pcond_type t)
+{
+ struct pcond_node *pn;
+
+ pn = grecs_zalloc (sizeof (*pn));
+ pn->type = t;
+ return pn;
+}
+
+static void
+pcond_node_free (struct pcond_node *node)
+{
+ if (!node)
+ return;
+ switch (node->type)
+ {
+ case pcond_not:
+ pcond_node_free (node->v.unary);
+ break;
+
+ case pcond_and:
+ case pcond_or:
+ pcond_node_free (node->v.binary[0]);
+ pcond_node_free (node->v.binary[1]);
+ break;
+
+ default:
+ break;
+ }
+ grecs_free (node);
+}
+
+static int
+pcond_eval (struct pcond_node *node, struct prog *p)
+{
+ if (!node)
+ return 0;
+ switch (node->type)
+ {
+ case pcond_true:
+ return 1;
+
+ case pcond_component:
+ return strcmp (p->tag, node->v.tag) == 0;
+
+ case pcond_type:
+ return p->type == node->v.type;
+
+ case pcond_mode:
+ return IS_COMPONENT (p) && p->v.p.comp->mode == node->v.mode;
+
+ case pcond_status:
+ return IS_COMPONENT (p) && p->v.p.status == node->v.status;
+
+ case pcond_not:
+ return !pcond_eval (node->v.unary, p);
+
+ case pcond_and:
+ if (!pcond_eval (node->v.binary[0], p))
+ return 0;
+ return pcond_eval (node->v.binary[1], p);
+
+ case pcond_or:
+ if (pcond_eval (node->v.binary[0], p))
+ return 1;
+ return pcond_eval (node->v.binary[1], p);
+
+ default:
+ abort ();
+ }
+}
+
+static int json_to_pcond (struct ctlio *io, struct json_value *val,
+ struct pcond_node **pnode);
+
+static int
+pcond_conv_component (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io)
+{
+ if (arg->type != json_string)
+ {
+ ctlio_reply (io, 400, "component must be string");
+ return -1;
+ }
+ node->v.tag = arg->v.s;
+ return 0;
+}
+
+static int
+pcond_conv_n (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io, char * const *ar, const char *what)
+{
+ int n;
+
+ if (arg->type != json_string)
+ {
+ ctlio_reply (io, 400, "%s must be string", what);
+ return -1;
+ }
+ n = array_index (ar, arg->v.s);
+ if (n == -1)
+ {
+ ctlio_reply (io, 400, "bad %s", what);
+ return -1;
+ }
+ return n;
+}
+
+static int
+pcond_conv_type (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io)
+{
+ int n = pcond_conv_n (node, arg, io, pies_type_str, "type");
+ if (n == -1)
+ return -1;
+ node->v.type = n;
+ return 0;
+}
+
+static int
+pcond_conv_mode (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io)
+{
+ int n = pcond_conv_n (node, arg, io, pies_type_str, "mode");
+ if (n == -1)
+ return -1;
+ node->v.mode = n;
+ return 0;
+}
+
+static int
+pcond_conv_status (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io)
+{
+ int n = pcond_conv_n (node, arg, io, pies_status_str, "status");
+ if (n == -1)
+ return -1;
+ node->v.status = n;
+ return 0;
+}
+static int
+pcond_conv_not (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io)
+{
+ return json_to_pcond (io, arg, &node->v.unary);
+}
+
+static int
+pcond_conv_binary (struct pcond_node *node, struct json_value *arg,
+ struct ctlio *io)
+{
+ struct json_value *v;
+
+ if (arg->type != json_arr)
+ {
+ ctlio_reply (io, 400, "arguments to binary opcode must be array");
+ return -1;
+ }
+ json_array_get (arg, 0, &v);
+ if (json_to_pcond (io, v, &node->v.binary[0]))
+ return -1;
+ json_array_get (arg, 1, &v);
+ if (json_to_pcond (io, v, &node->v.binary[1]))
+ return -1;
+ return 0;
+}
+
+struct pcond_conv {
+ char *term;
+ int (*handler) (struct pcond_node *, struct json_value *arg, struct ctlio *);
+};
+
+static struct pcond_conv pcond_conv[] = {
+ [pcond_true] = { "true", NULL },
+ [pcond_component] = { "component", pcond_conv_component },
+ [pcond_type] = { "type", pcond_conv_type },
+ [pcond_mode] = { "mode", pcond_conv_mode },
+ [pcond_status] = { "status", pcond_conv_status },
+ [pcond_not] = { "not", pcond_conv_not },
+ [pcond_and] = { "and", pcond_conv_binary },
+ [pcond_or] = { "or", pcond_conv_binary },
+};
+
+static int max_type = sizeof (pcond_conv) / sizeof (pcond_conv[0]);
+
+static int
+pcond_conv_find (char const *name)
+{
+ int i;
+ for (i = 0; i < max_type; i++)
+ {
+ if (strcmp (pcond_conv[i].term, name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static int
+object_to_cond (struct ctlio *io, struct json_value *obj,
+ struct pcond_node **pnode)
+{
+ struct json_value *op, *arg;
+ struct pcond_node *node;
+ int type;
+
+ if (json_object_get (obj, "op", &op))
+ {
+ ctlio_reply (io, 400, "bad conditional: missing op");
+ return -1;
+ }
+ if (json_object_get (obj, "arg", &arg))
+ {
+ ctlio_reply (io, 400, "bad conditional: missing arg");
+ return -1;
+ }
+
+ if (op->type != json_string)
+ {
+ ctlio_reply (io, 400, "bad conditional: bad op type");
+ return -1;
+ }
+
+ type = pcond_conv_find (op->v.s);
+ if (type == -1)
+ {
+ ctlio_reply (io, 400, "bad conditional: unknown opcode");
+ return -1;
+ }
+
+ node = pcond_node_alloc (type);
+ if (pcond_conv[type].handler && pcond_conv[type].handler (node, arg, io))
+ {
+ pcond_node_free (node);
+ return -1;
+ }
+ *pnode = node;
+ return 0;
+}
+
+static int
+json_to_pcond (struct ctlio *io, struct json_value *val,
+ struct pcond_node **pnode)
+{
+ if (!val)
+ *pnode = pcond_node_alloc (pcond_true);
+ else
+ switch (val->type)
+ {
+ case json_null:
+ *pnode = NULL;
+ break;
+
+ case json_bool:
+ if (val->v.b)
+ *pnode = pcond_node_alloc (pcond_true);
+ else
+ *pnode = NULL;
+ break;
+
+ case json_number:
+ case json_string:
+ case json_arr:
+ ctlio_reply (io, 400, "bad conditional");
+ return -1;
+
+ case json_object:
+ return object_to_cond (io, val, pnode);
+ }
+ return 0;
+}
+
+static struct json_value *prog_serialize (struct prog *prog);
+
+static int
+selector (struct prog *prog, void *data)
+{
+ struct eval_env *env = data;
+
+ if (auth_prog (prog, env->io) && pcond_eval (env->cond, prog))
+ json_array_append (env->result, prog_serialize (prog));
+ return 0;
+}
+
static struct json_value *
prog_serialize (struct prog *prog)
{
@@ -1370,7 +1688,7 @@ prog_serialize (struct prog *prog)
{
case TYPE_COMPONENT:
FORMAT_IDX (ret, "mode", pies_comp_mode_str, prog->v.p.comp->mode);
- FORMAT_IDX (ret, "status", status_str, prog->v.p.status);
+ FORMAT_IDX (ret, "status", pies_status_str, prog->v.p.status);
if (prog->pid)
json_object_set_number (ret, "PID", prog->pid);
@@ -1402,6 +1720,33 @@ prog_serialize (struct prog *prog)
}
static void
+component_stop (struct ctlio *io, struct prog *prog)
+{
+ if (prog->v.p.comp->flags & CF_DISABLED)
+ ctlio_reply (io, 409, "already stopped");
+ else
+ {
+ progman_stop_component (prog);
+ prog->v.p.comp->flags |= CF_DISABLED;
+ ctlio_reply (io, 200, "Component stopped");
+ }
+}
+
+static void
+component_start (struct ctlio *io, struct prog *prog)
+{
+ if (!(prog->v.p.comp->flags & CF_DISABLED))
+ ctlio_reply (io, 409, "already running");
+ else
+ {
+ prog->v.p.comp->flags &= ~CF_DISABLED;
+ prog->v.p.status = status_enabled;
+ kill (getpid (), SIGALRM);
+ ctlio_reply (io, 200, "Component started");
+ }
+}
+
+static void
res_programs (struct ctlio *io, enum http_method meth,
size_t pathc, char **pathv,
struct json_value *json)
@@ -1411,9 +1756,12 @@ res_programs (struct ctlio *io, enum http_method meth,
struct eval_env env;
env.io = io;
- env.json = json_new_array ();
+ if (json_to_pcond (io, json, &env.cond))
+ return;
+ env.result = json_new_array ();
progman_foreach (selector, &env);
- io->output.reply = env.json;
+ pcond_node_free (env.cond);
+ io->output.reply = env.result;
io->code = 200;
}
else if (meth == METH_DELETE || meth == METH_PUT)
@@ -1431,32 +1779,38 @@ res_programs (struct ctlio *io, enum http_method meth,
ctlio_reply (io, 404, "Not a component");
else if (meth == METH_DELETE)
{
- if (prog->v.p.comp->flags & CF_DISABLED)
- ctlio_reply (io, 409, "already stopped");
- else
- {
- progman_stop_component (prog);
- prog->v.p.comp->flags |= CF_DISABLED;
- ctlio_reply (io, 200, "Component stopped");
- }
+ component_stop (io, prog);
}
else
{
- if (!(prog->v.p.comp->flags & CF_DISABLED))
- ctlio_reply (io, 409, "already running");
- else
- {
- prog->v.p.comp->flags &= ~CF_DISABLED;
- prog->v.p.status = status_enabled;
- kill (getpid (), SIGALRM);
- ctlio_reply (io, 200, "Component started");
- }
+ component_start (io, prog);
}
}
else
ctlio_reply (io, 403, NULL);
}
}
+ else if (meth == METH_POST)
+ {
+ if (json->type != json_arr)
+ {
+ ctlio_reply (io, 400, NULL);
+ }
+ else
+ {
+ size_t i, n;
+
+ n = json_array_size (json);
+ for (i = 0; i < n; i++)
+ {
+ struct json_value *v;
+ if (json_array_get (json, i, &v) == 0 && v->type == json_string)
+ progman_stop_tag (v->v.s);
+ }
+ kill (getpid (), SIGALRM);
+ }
+ ctlio_reply (io, 200, "Done");
+ }
else
ctlio_reply (io, 405, NULL);
}

Return to:

Send suggestions and report system problems to the System administrator.