aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/arraymember.c17
-rw-r--r--lib/libpies.h3
-rw-r--r--src/cmdline.opt4
-rw-r--r--src/ctl.c442
-rw-r--r--src/pies.c161
-rw-r--r--src/pies.h6
-rw-r--r--src/piesctl-cl.opt2
-rw-r--r--src/piesctl.c247
-rw-r--r--src/progman.c136
9 files changed, 703 insertions, 315 deletions
diff --git a/lib/arraymember.c b/lib/arraymember.c
index 14ace99..010f4a1 100644
--- a/lib/arraymember.c
+++ b/lib/arraymember.c
@@ -1,5 +1,5 @@
/* This file is part of GNU Pies.
- Copyright (C) 2007, 2008, 2009, 2010, 2013 Sergey Poznyakoff
+ Copyright (C) 2015, 2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
#include "libpies.h"
int
-is_array_member (char * const * ar, char const *str)
+is_array_member (char * const *ar, char const *str)
{
for (; *ar; ++ar)
{
@@ -31,3 +31,16 @@ is_array_member (char * const * ar, char const *str)
return 0;
}
+int
+array_index (char * const *ar, char const *str)
+{
+ int i;
+
+ for (i = 0; ar[i]; i++)
+ {
+ if (strcmp (ar[i], str) == 0)
+ return i;
+ }
+ return -1;
+}
+
diff --git a/lib/libpies.h b/lib/libpies.h
index dab36df..b04182e 100644
--- a/lib/libpies.h
+++ b/lib/libpies.h
@@ -1,5 +1,5 @@
/* This file is part of GNU Pies.
- Copyright (C) 2009, 2010, 2011, 2013, 2015 Sergey Poznyakoff
+ Copyright (C) 2009-2011, 2013, 2015, 2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -51,6 +51,7 @@ int strtotok_ci (struct tokendef *tab, const char *str, int *pres);
int toktostr (struct tokendef *tab, int tok, const char **pres);
int is_array_member (char * const * ar, char const *str);
+int array_index (char * const *ar, char const *str);
int strsplit3 (const char *input, char *result[3], int flag);
/* url.c */
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 18791b6..e425518 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -1,5 +1,5 @@
/* This file is part of GNU Pies. -*- c -*-
- Copyright (C) 2008-2014 Sergey Poznyakoff
+ Copyright (C) 2008-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ OPTIONS_BEGIN("pies",
[<process invocation and execution supervisor>],
[<>],
[<gnu>],
- [<copyright_year=2008-2014>],
+ [<copyright_year=2008-2016>],
[<copyright_holder=Sergey Poznyakoff>])
GROUP(Operation Mode)
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);
}
diff --git a/src/pies.c b/src/pies.c
index 5f5d955..bbbc367 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -1,5 +1,5 @@
/* This file is part of GNU Pies.
- Copyright (C) 2008-2011, 2013-2015 Sergey Poznyakoff
+ Copyright (C) 2008-2011, 2013-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,8 +45,6 @@ enum pies_command command;
char *statedir = DEFAULT_STATE_DIR;
char *instance;
char *pidfile;
-char *ctlfile;
-char *statfile;
char *qotdfile;
int inetd_mode;
mode_t pies_umask = 0;
@@ -1581,16 +1579,16 @@ struct grecs_keyword pies_keywords[] = {
},
{"control-file",
NULL,
- N_("Set location of the control file."),
- grecs_type_string, GRECS_DFLT,
- &ctlfile, 0,
+ N_("Ignored for compatibility with version 1.2."),
+ grecs_type_string, GRECS_DFLT|GRECS_INAC,
+ NULL, 0,
NULL,
},
{"stat-file",
NULL,
- N_("Set location of the statistics output file."),
- grecs_type_string, GRECS_DFLT,
- &statfile, 0,
+ N_("Ignored for compatibility with version 1.2."),
+ grecs_type_string, GRECS_DFLT|GRECS_INAC,
+ NULL, 0,
NULL,
},
{"qotd-file",
@@ -1802,14 +1800,6 @@ sig_handler (int sig)
case SIGALRM:
got_alarm = 1;
break;
-
- case SIGUSR1:
- action = ACTION_COMPRELOAD;
- break;
-
- case SIGUSR2:
- action = ACTION_DUMPSTATS;
- break;
}
}
@@ -1839,8 +1829,6 @@ static int default_sigv[] = {
SIGINT,
SIGHUP,
SIGALRM,
- SIGUSR1,
- SIGUSR2,
SIGPIPE
};
@@ -1924,86 +1912,49 @@ enum pies_status
pies_check_status (pid_t *ppid)
{
pid_t pid = pidfile_read (0);
- int i;
- int rc;
if (pid <= 0)
return pies_status_ctr;
*ppid = pid;
- if (kill (pid, SIGUSR2))
+ if (kill (pid, 0))
return pies_status_stale;
- for (i = 0; i < 4 && (rc = access (statfile, R_OK)); i++)
- sleep (1);
-
- if (rc)
- return pies_status_noresp;
return pies_status_running;
}
-
void
-stop_components ()
+request_restart_components (size_t cc, char **cv)
{
- FILE *fp;
- size_t size = 0;
- char *buf = NULL;
-
- logmsg (LOG_INFO, _("stopping components"));
-
- fp = fopen (ctlfile, "r");
- if (!fp)
- {
- logmsg (LOG_ERR, _("cannot open control file `%s': %s"),
- ctlfile, strerror (errno));
- return;
- }
- if (unlink (ctlfile))
- {
- logmsg (LOG_ERR, _("cannot unlink control file `%s': %s"),
- ctlfile, strerror (errno));
- fclose (fp);
- return;
- }
-
- while (getline (&buf, &size, fp) > 0)
- {
- size_t len = strlen (buf);
- if (len == 0)
- continue;
- if (buf[len - 1] == '\n')
- buf[len - 1] = 0;
- progman_stop_tag (buf);
- }
-
- free (buf);
- fclose (fp);
+ char **argv;
+ size_t i;
+
+ argv = xcalloc (cc + 4, sizeof (*argv));
+ argv[0] = "piesctl";
+ argv[1] = "--url";
+ argv[2] = (char*) pies_control_url ();
+ for (i = 0; i < cc; i++)
+ argv[3 + i] = cv[i];
+ argv[3 + i] = NULL;
+ execv (argv[0], argv);
+ logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno));
+ exit (EX_OSFILE);
}
-int
-request_restart_components (char **argv)
+void
+list_components (void)
{
- FILE *fp;
- pid_t pid = pidfile_read (1);//FIXME: useless in init mode, init has pid == 1
-
- if (pid == -1)
- return 1;
-
- fp = fopen (ctlfile, "w");
- if (!fp)
- {
- logmsg (LOG_ERR, _("cannot open control file `%s': %s"),
- ctlfile, strerror (errno));
- return 1;
- }
- for (; *argv; argv++)
- fprintf (fp, "%s\n", *argv);
- fclose (fp);
-
- kill (pid, SIGUSR1);
- return 0;
+ char *argv[5];
+
+ argv[0] = "piesctl";
+ argv[1] = "--url";
+ argv[2] = (char*) pies_control_url ();
+ argv[3] = "list";
+ argv[4] = NULL;
+ execv (argv[0], argv);
+ logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno));
+ exit (EX_OSFILE);
}
@@ -2026,11 +1977,7 @@ int
pies_status ()
{
pid_t pid;
- FILE *fp;
- if (unlink (statfile) && errno != ENOENT)
- logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
- statfile, strerror (errno));
switch (pies_check_status (&pid))
{
case pies_status_ctr:
@@ -2047,27 +1994,11 @@ pies_status ()
logmsg (LOG_INFO,
_("pies seems to run with pid %lu, but is not responding"),
(unsigned long) pid);
- if (unlink (statfile))
- logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
- statfile, strerror (errno));
return 2;
case pies_status_running:
- fp = fopen (statfile, "r");
- if (!fp)
- logmsg (LOG_ERR, _("cannot open statfile `%s': %s"),
- statfile, strerror (errno));
- else
- {
- char c;
-
- if (unlink (statfile))
- logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
- statfile, strerror (errno));
- while ((c = fgetc (fp)) != EOF)
- fputc (c, stdout);
- fclose (fp);
- }
+ list_components ();
+ break;
}
return 0;
}
@@ -2188,10 +2119,6 @@ set_state_file_names (const char *base)
{
if (!pidfile)
pidfile = mkfilename (statedir, base, ".pid");
- if (!ctlfile)
- ctlfile = mkfilename (statedir, base, ".ctl");
- if (!statfile)
- statfile = mkfilename (statedir, base, ".stat");
if (!qotdfile)
qotdfile = mkfilename (statedir, base, ".qotd");
}
@@ -2366,8 +2293,8 @@ main (int argc, char **argv)
pies_priv_setup (&pies_privs);
if (pies_umask)
umask (pies_umask);
- exit (request_restart_components (argv + index));
-
+ request_restart_components (argc - index, argv + index);
+
case COM_RELOAD:
exit (pies_reload ());
@@ -2458,18 +2385,6 @@ main (int argc, char **argv)
pies_pause ();
switch (action)
{
- case ACTION_COMPRELOAD:
- stop_components ();
- progman_cleanup (0);
- progman_start ();
- action = ACTION_CONT;
- break;
-
- case ACTION_DUMPSTATS:
- progman_dump_stats (statfile);
- action = ACTION_CONT;
- break;
-
case ACTION_STOP:
case ACTION_RESTART:
if (init_process)
diff --git a/src/pies.h b/src/pies.h
index afdac66..4bc57bd 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -1,5 +1,5 @@
/* This file is part of GNU Pies.
- Copyright (C) 2008, 2009, 2010, 2011, 2013-2015 Sergey Poznyakoff
+ Copyright (C) 2008-2011, 2013-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -267,8 +267,6 @@ enum pies_action {
ACTION_CONT,
ACTION_STOP,
ACTION_RESTART,
- ACTION_COMPRELOAD,
- ACTION_DUMPSTATS,
ACTION_CTRLALTDEL,
ACTION_KBREQUEST
};
@@ -317,7 +315,6 @@ void progman_cleanup (int expect_term);
void progman_filter (int (*filter) (struct component *, void *data),
void *data);
void progman_stop_tag (const char *name);
-void progman_dump_stats (const char *filename);
void progman_dump_prereq (void);
void progman_dump_depmap (void);
int progman_accept (int socket, void *data);
@@ -541,3 +538,4 @@ struct control
extern struct control control;
void ctl_open(void);
+char const *pies_control_url (void);
diff --git a/src/piesctl-cl.opt b/src/piesctl-cl.opt
index a83616e..d026269 100644
--- a/src/piesctl-cl.opt
+++ b/src/piesctl-cl.opt
@@ -18,7 +18,7 @@ OPTIONS_BEGIN("piesctl",
[<GNU pies control program>],
[<COMMAND [ARG...]>],
[<gnu>],
- [<copyright_year=2008-2015>],
+ [<copyright_year=2008-2016>],
[<copyright_holder=Sergey Poznyakoff>])
OPTION(instance,i,NAME,
diff --git a/src/piesctl.c b/src/piesctl.c
index 9c5ef8b..626463c 100644
--- a/src/piesctl.c
+++ b/src/piesctl.c
@@ -622,7 +622,6 @@ send_header (void *sym, void *data)
static void
shttp_request_send (struct shttp_connection *conn, int method, char const *uri)
{
- shttp_io_init (&conn->req);
shttp_send_line (conn, "%s %s %s", method_names[method], uri, http_version);
shttp_send_line (conn, "Host: %s",
conn->url->host ? conn->url->host : "localhost");
@@ -1160,10 +1159,229 @@ print_comp (FILE *fp, struct json_value *v, size_t n)
fputc ('\n', fp);
}
+struct pcond_parser_state
+{
+ int argc;
+ char **argv;
+};
+
+static char *
+next_token (struct pcond_parser_state *state)
+{
+ if (state->argc == 0)
+ return NULL;
+ --state->argc;
+ return *state->argv++;
+}
+
+static char const *
+peek_token (struct pcond_parser_state *state)
+{
+ if (state->argc == 0)
+ return NULL;
+ return *state->argv;
+}
+
+static struct json_value *
+json_new_array2 (struct json_value *a, struct json_value *b)
+{
+ struct json_value *ret = json_new_array ();
+ json_array_append (ret, a);
+ json_array_append (ret, b);
+ return ret;
+}
+
+static struct json_value *
+json_encode_op (char const *op, struct json_value *arg)
+{
+ struct json_value *ret = json_new_object ();
+ json_object_set (ret, "op", json_new_string (op));
+ json_object_set (ret, "arg", arg);
+ return ret;
+}
+
+static void pcond_parse_or (struct pcond_parser_state *, struct json_value **);
+
+static void
+pcond_parse_unary (struct pcond_parser_state *state, struct json_value **ret)
+{
+ char const *term = next_token (state);
+
+ if (!term)
+ *ret = json_new_bool (1);
+ else
+ {
+ static char *arg_terms[] = {
+ "type", "mode", "status", "component", NULL
+ };
+
+ if (strcasecmp (term, "all") == 0)
+ *ret = json_new_bool (1);
+ else if (is_array_member (arg_terms, term))
+ {
+ if (!peek_token (state))
+ {
+ grecs_error (NULL, 0, _("%s requires argument"), term);
+ exit (EX_USAGE);
+ }
+ *ret = json_encode_op (term, json_new_string (next_token (state)));
+ }
+ else if (strcasecmp (term, "not") == 0)
+ {
+ struct json_value *val;
+ if (!peek_token (state))
+ {
+ grecs_error (NULL, 0, _("%s requires argument"), term);
+ exit (EX_USAGE);
+ }
+ pcond_parse_unary (state, &val);
+ *ret = json_encode_op (term, val);
+ }
+ else if (term[0] == '(')
+ {
+ pcond_parse_or (state, ret);
+ term = next_token (state);
+ if (!term || term[0] != ')')
+ {
+ grecs_error (NULL, 0, _("unbalanced parentesis"));
+ exit (EX_USAGE);
+ }
+ }
+ else
+ {
+ grecs_error (NULL, 0, _("parse error at %s"), term);
+ exit (EX_USAGE);
+ }
+ }
+}
+
+static void
+pcond_parse_and (struct pcond_parser_state *state, struct json_value **ret)
+{
+ char const *token;
+ struct json_value *left, *right;
+
+ pcond_parse_unary (state, &left);
+ token = peek_token (state);
+ if (!token || strcmp (token, "and"))
+ {
+ *ret = left;
+ return;
+ }
+ next_token (state);
+ pcond_parse_and (state, &right);
+ *ret = json_encode_op (token, json_new_array2 (left, right));
+}
+
+static void
+pcond_parse_or (struct pcond_parser_state *state, struct json_value **ret)
+{
+ char const *token;
+ struct json_value *left, *right;
+
+ pcond_parse_and (state, &left);
+ token = peek_token (state);
+ if (!token || strcmp (token, "or"))
+ {
+ *ret = left;
+ return;
+ }
+ next_token (state);
+ pcond_parse_or (state, &right);
+ *ret = json_encode_op (token, json_new_array2 (left, right));
+}
+
+static struct json_value *
+parse_condition (int argc, char **argv)
+{
+ struct json_value *val = NULL;
+
+ if (argc > 1)
+ {
+ struct pcond_parser_state state;
+ state.argc = argc - 1;
+ state.argv = argv + 1;
+ pcond_parse_or (&state, &val);
+ if (state.argc)
+ {
+ grecs_error (NULL, 0,
+ _("expected end of statement, but found \"%s\""),
+ *state.argv);
+ exit (EX_USAGE);
+ }
+#if 0
+ print_json (stdout, val);
+ exit (0);
+#endif
+ }
+ return val;
+}
+
+static void
+acc_writer (void *closure, char const *text, size_t len)
+{
+ grecs_txtacc_grow ((struct grecs_txtacc *)closure, text, len);
+}
+
+static char *
+json_to_string (struct json_value *val)
+{
+ struct grecs_txtacc *acc = grecs_txtacc_create ();
+ struct json_format fmt = {
+ .indent = 0,
+ .precision = 0,
+ .write = acc_writer,
+ .data = acc
+ };
+ char *ret;
+
+ json_format_value (val, &fmt);
+ grecs_txtacc_grow_char (acc, 0);
+ ret = grecs_txtacc_finish (acc, 1);
+ grecs_txtacc_free (acc);
+
+ return ret;
+}
+
+static char *
+parse_condition_to_uri (char const *base, int argc, char **argv)
+{
+ char *ret = NULL;
+ struct grecs_txtacc *acc;
+ struct json_value *val;
+
+ acc = grecs_txtacc_create ();
+ grecs_txtacc_grow_string (acc, base);
+
+ val = parse_condition (argc, argv);
+ if (val)
+ {
+ struct json_format fmt = {
+ .indent = 0,
+ .precision = 0,
+ .write = acc_writer,
+ .data = acc
+ };
+ grecs_txtacc_grow_char (acc, '/');
+ json_format_value (val, &fmt);
+ json_value_free (val);
+ }
+ grecs_txtacc_grow_char (acc, 0);
+
+ ret = grecs_txtacc_finish (acc, 1);
+ grecs_txtacc_free (acc);
+
+ return ret;
+}
+
static int
com_list (struct shttp_connection *conn, int argc, char **argv)
{
- shttp_process (conn, METH_GET, "/programs");
+ char *uri = parse_condition_to_uri ("/programs", argc, argv);
+
+ shttp_io_init (&conn->req);
+ shttp_process (conn, METH_GET, uri);
+ grecs_free (uri);
if (!dump && conn->result && conn->result->type == json_arr)
{
size_t i, n = json_array_size (conn->result);
@@ -1190,6 +1408,7 @@ com_stop (struct shttp_connection *conn, int argc, char **argv)
{
struct json_value *v;
grecs_asprintf (&buf, &len, "/programs/%s", argv[i]);
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_DELETE, buf);
v = shttp_getval (conn, "error_message", json_string);
if (v)
@@ -1210,6 +1429,7 @@ com_start (struct shttp_connection *conn, int argc, char **argv)
{
struct json_value *v;
grecs_asprintf (&buf, &len, "/programs/%s", argv[i]);
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_PUT, buf);
v = shttp_getval (conn, "error_message", json_string);
if (v)
@@ -1222,7 +1442,24 @@ com_start (struct shttp_connection *conn, int argc, char **argv)
static int
com_restart (struct shttp_connection *conn, int