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,3 +1,3 @@
/* This file is part of GNU Pies.
- Copyright (C) 2007, 2008, 2009, 2010, 2013 Sergey Poznyakoff
+ Copyright (C) 2015, 2016 Sergey Poznyakoff
@@ -23,3 +23,3 @@
int
-is_array_member (char * const * ar, char const *str)
+is_array_member (char * const *ar, char const *str)
{
@@ -33 +33,14 @@ is_array_member (char * const * ar, char const *str)
+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,3 +1,3 @@
/* 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
@@ -53,2 +53,3 @@ 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);
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 18791b6..e425518 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -1,3 +1,3 @@
/* This file is part of GNU Pies. -*- c -*-
- Copyright (C) 2008-2014 Sergey Poznyakoff
+ Copyright (C) 2008-2016 Sergey Poznyakoff
@@ -20,3 +20,3 @@ OPTIONS_BEGIN("pies",
[<gnu>],
- [<copyright_year=2008-2014>],
+ [<copyright_year=2008-2016>],
[<copyright_holder=Sergey Poznyakoff>])
diff --git a/src/ctl.c b/src/ctl.c
index cbc5fea..4f56923 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -1002,4 +1002,16 @@ ctlio_do_command (struct ctlio *io, struct wordsplit *uri)
}
+ 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);
@@ -1140,7 +1152,5 @@ ctl_accept (int socket, void *data)
-void
-ctl_open ()
+char const *
+pies_control_url (void)
{
- int fd;
-
if (!control.url)
@@ -1152,3 +1162,3 @@ ctl_open ()
str, strerror (errno));
- return;
+ exit (EX_OSERR);
}
@@ -1156,3 +1166,11 @@ ctl_open ()
}
-
+ return control.url->string;
+}
+
+void
+ctl_open ()
+{
+ int fd;
+
+ pies_control_url ();
fd = create_socket (control.url, SOCK_STREAM, NULL, 077);
@@ -1273,3 +1291,4 @@ struct eval_env
struct ctlio *io;
- struct json_value *json;
+ struct pcond_node *cond;
+ struct json_value *result;
};
@@ -1301,16 +1320,4 @@ auth_prog (struct prog *prog, struct ctlio *io)
}
-
-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",
@@ -1320,3 +1327,3 @@ static char const *pies_type_str[] = {
-static char const *pies_comp_mode_str[] = {
+static char * const pies_comp_mode_str[] = {
[pies_comp_exec] = "exec",
@@ -1339,3 +1346,3 @@ static char const *pies_comp_mode_str[] = {
-static char const *status_str[] = {
+static char * const pies_status_str[] = {
[status_enabled] = "enabled",
@@ -1350,3 +1357,3 @@ 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)
{
@@ -1358,3 +1365,314 @@ format_idx (struct json_value *obj, const char *name, unsigned 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 *
@@ -1372,3 +1690,3 @@ prog_serialize (struct prog *prog)
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);
@@ -1404,2 +1722,29 @@ 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,
@@ -1413,5 +1758,8 @@ res_programs (struct ctlio *io, enum http_method meth,
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;
@@ -1433,10 +1781,3 @@ res_programs (struct ctlio *io, enum http_method meth,
{
- 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);
}
@@ -1444,11 +1785,3 @@ res_programs (struct ctlio *io, enum http_method meth,
{
- 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);
}
@@ -1459,2 +1792,23 @@ res_programs (struct ctlio *io, enum http_method meth,
}
+ 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
diff --git a/src/pies.c b/src/pies.c
index 5f5d955..bbbc367 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -1,3 +1,3 @@
/* This file is part of GNU Pies.
- Copyright (C) 2008-2011, 2013-2015 Sergey Poznyakoff
+ Copyright (C) 2008-2011, 2013-2016 Sergey Poznyakoff
@@ -47,4 +47,2 @@ char *instance;
char *pidfile;
-char *ctlfile;
-char *statfile;
char *qotdfile;
@@ -1583,5 +1581,5 @@ struct grecs_keyword pies_keywords[] = {
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,
@@ -1590,5 +1588,5 @@ struct grecs_keyword pies_keywords[] = {
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,
@@ -1804,10 +1802,2 @@ sig_handler (int sig)
break;
-
- case SIGUSR1:
- action = ACTION_COMPRELOAD;
- break;
-
- case SIGUSR2:
- action = ACTION_DUMPSTATS;
- break;
}
@@ -1841,4 +1831,2 @@ static int default_sigv[] = {
SIGALRM,
- SIGUSR1,
- SIGUSR2,
SIGPIPE
@@ -1926,4 +1914,2 @@ pies_check_status (pid_t *ppid)
pid_t pid = pidfile_read (0);
- int i;
- int rc;
@@ -1934,10 +1920,5 @@ pies_check_status (pid_t *ppid)
- 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;
@@ -1945,63 +1926,33 @@ pies_check_status (pid_t *ppid)
-
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);
}
@@ -2028,7 +1979,3 @@ 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))
@@ -2049,5 +1996,2 @@ pies_status ()
(unsigned long) pid);
- if (unlink (statfile))
- logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
- statfile, strerror (errno));
return 2;
@@ -2055,17 +1999,4 @@ pies_status ()
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;
}
@@ -2190,6 +2121,2 @@ set_state_file_names (const char *base)
pidfile = mkfilename (statedir, base, ".pid");
- if (!ctlfile)
- ctlfile = mkfilename (statedir, base, ".ctl");
- if (!statfile)
- statfile = mkfilename (statedir, base, ".stat");
if (!qotdfile)
@@ -2368,4 +2295,4 @@ main (int argc, char **argv)
umask (pies_umask);
- exit (request_restart_components (argv + index));
-
+ request_restart_components (argc - index, argv + index);
+
case COM_RELOAD:
@@ -2460,14 +2387,2 @@ main (int argc, char **argv)
{
- 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:
diff --git a/src/pies.h b/src/pies.h
index afdac66..4bc57bd 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -1,3 +1,3 @@
/* 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
@@ -269,4 +269,2 @@ enum pies_action {
ACTION_RESTART,
- ACTION_COMPRELOAD,
- ACTION_DUMPSTATS,
ACTION_CTRLALTDEL,
@@ -319,3 +317,2 @@ void progman_filter (int (*filter) (struct component *, void *data),
void progman_stop_tag (const char *name);
-void progman_dump_stats (const char *filename);
void progman_dump_prereq (void);
@@ -543 +540,2 @@ 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
@@ -20,3 +20,3 @@ OPTIONS_BEGIN("piesctl",
[<gnu>],
- [<copyright_year=2008-2015>],
+ [<copyright_year=2008-2016>],
[<copyright_holder=Sergey Poznyakoff>])
diff --git a/src/piesctl.c b/src/piesctl.c
index 9c5ef8b..626463c 100644
--- a/src/piesctl.c
+++ b/src/piesctl.c
@@ -624,3 +624,2 @@ 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);
@@ -1162,2 +1161,217 @@ print_comp (FILE *fp, struct json_value *v, size_t n)
+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
@@ -1165,3 +1379,7 @@ 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)
@@ -1192,2 +1410,3 @@ com_stop (struct shttp_connection *conn, int argc, char **argv)
grecs_asprintf (&buf, &len, "/programs/%s", argv[i]);
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_DELETE, buf);
@@ -1212,2 +1431,3 @@ com_start (struct shttp_connection *conn, int argc, char **argv)
grecs_asprintf (&buf, &len, "/programs/%s", argv[i]);
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_PUT, buf);
@@ -1224,3 +1444,20 @@ com_restart (struct shttp_connection *conn, int argc, char **argv)
{
- abort ();
+ struct json_value *val = json_new_array ();
+ size_t i;
+
+ if (argc == 1)
+ {
+ grecs_error (NULL, 0, _("missing component names"));
+ exit (EX_USAGE);
+ }
+ for (i = 1; i < argc; i++)
+ json_array_append (val, json_new_string (argv[i]));
+
+ shttp_io_init (&conn->req);
+ conn->req.content = json_to_string (val);
+ conn->req.content_length = strlen (conn->req.content);
+ json_value_free (val);
+
+ shttp_process (conn, METH_POST, "/programs");
+
return 0;
@@ -1243,2 +1480,3 @@ com_id (struct shttp_connection *conn, int argc, char **argv)
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_GET, "/instance");
@@ -1264,2 +1502,3 @@ com_id (struct shttp_connection *conn, int argc, char **argv)
grecs_asprintf (&buf, &size, "/instance/%s", argv[i]);
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_GET, buf);
@@ -1279,2 +1518,3 @@ com_shutdown (struct shttp_connection *conn, int argc, char **argv)
{
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_DELETE, "/instance/PID");
@@ -1286,2 +1526,3 @@ com_reboot (struct shttp_connection *conn, int argc, char **argv)
{
+ shttp_io_init (&conn->req);
shttp_process (conn, METH_PUT, "/instance/PID");
diff --git a/src/progman.c b/src/progman.c
index 8c33db8..216fb72 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -1,3 +1,3 @@
/* This file is part of GNU Pies.
- Copyright (C) 2007-2013 Sergey Poznyakoff
+ Copyright (C) 2007-2016 Sergey Poznyakoff
@@ -2471,136 +2471,2 @@ progman_stop_tag (const char *name)
}
-
-void
-progman_dump_stats (const char *filename)
-{
- FILE *fp;
- struct prog *prog;
- char *tmpfile = NULL;
-
- if (asprintf (&tmpfile, "%s.%lu", filename, (unsigned long) getpid ()) == -1)
- {
- logmsg (LOG_ERR, "%s", strerror (ENOMEM));
- return;
- }
- logmsg (LOG_INFO, _("dumping statistics to `%s'"), tmpfile);
- fp = fopen (tmpfile, "w");
- if (!fp)
- {
- logmsg (LOG_ERR, _("cannot open file `%s' for writing: %s"),
- tmpfile, strerror (errno));
- return;
- }
-
- for (prog = proghead; prog; prog = prog->next)
- {
- int i;
- char fbuf[5];
- int fidx = 0;
-
- fprintf (fp, "%-16s ", prog->tag);
- switch (prog->type)
- {
- case TYPE_COMPONENT:
- switch (prog->v.p.comp->mode)
- {
- case pies_comp_exec:
- fbuf[fidx++] = 'C';
- break;
-
- case pies_comp_once:
- fbuf[fidx++] = 'c';
- break;
-
- case pies_comp_accept:
- fbuf[fidx++] = 'A';
- break;
-
- case pies_comp_inetd:
- fbuf[fidx++] = 'I';
- break;
-
- case pies_comp_pass_fd:
- fbuf[fidx++] = 'P';
-
- default:
- break;
- }
-
- switch (prog->v.p.status)
- {
- case status_enabled:
- fbuf[fidx++] = (prog->pid != 0) ? 'R' : ' ';
- break;
-
- case status_disabled:
- fbuf[fidx++] = 'D';
- break;
-
- case status_listener:
- fbuf[fidx++] = 'L';
- break;
-
- case status_sleeping:
- fbuf[fidx++] = 's';
- break;
-
- case status_stopping:
- fbuf[fidx++] = 'S';
- break;
-
- case status_finished:
- fbuf[fidx++] = 'f';
- }
- break;
-
- case TYPE_REDIRECTOR:
- fbuf[fidx++] = 'R';
- break;
-
- case TYPE_COMMAND:
- fbuf[fidx++] = 'E';
- }
-