From c221897e72debfb161365c28f08d7f4bac5511e5 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 31 Oct 2015 17:14:07 +0200 Subject: Implement list control command. * src/ctl.c: Implement list. * src/prog.h (IS_COMPONENT): New macro (from progman.c) * src/progman.c: Move IS_COMPONENT to src/prog.h * src/socket.c (create_socket): Clear uid, gid and umaskval for inet sockets. --- src/ctl.c | 468 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/pies.h | 2 +- src/prog.h | 2 + src/progman.c | 4 +- src/socket.c | 4 + 5 files changed, 470 insertions(+), 10 deletions(-) diff --git a/src/ctl.c b/src/ctl.c index cfa0e13..b1649f5 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -110,6 +110,7 @@ static void cmd_quit (struct ctlio *, size_t, char **); static void cmd_noop (struct ctlio *, size_t, char **); static void cmd_help (struct ctlio *, size_t, char **); static void cmd_id (struct ctlio *, size_t, char **); +static void cmd_list (struct ctlio *, size_t, char **); struct ctlio_command { @@ -130,6 +131,8 @@ static struct ctlio_command cmdtab[] = { CTL_ALL_STATES, 1, 1, cmd_quit }, { "help", "display help", CTL_ALL_STATES, 1, 1, cmd_help }, + { "list", "list components", + CTL_AUTHENTICATED_STATE, 1, 0, cmd_list }, { NULL } }; @@ -161,10 +164,14 @@ ctlio_create (void) struct ctlio *io; io = xmalloc (sizeof (*io)); - io->state = CTL_INITIAL_STATE; + io->state = CTL_AUTHENTICATED_STATE; //FIXME CTL_INITIAL_STATE; ctlbuf_init (&io->ibuf); ctlbuf_init (&io->obuf); - io->wsflags = WRDSF_DEFFLAGS; + io->ws.ws_delim = " \t()"; + io->wsflags = WRDSF_DELIM | + WRDSF_NOVAR | WRDSF_NOCMD | + WRDSF_QUOTE | WRDSF_RETURN_DELIMS | + WRDSF_WS; return io; } @@ -305,12 +312,12 @@ static void cmd_id (struct ctlio *io, size_t argc, char **argv) { ctlio_reply (io, "110", "instance identification follows"); - ctlio_printf (io, "Package:%s%s", PACKAGE_NAME, CRLF); - ctlio_printf (io, "Version:%s%s", PACKAGE_VERSION, CRLF); + ctlio_printf (io, "Package: %s%s", PACKAGE_NAME, CRLF); + ctlio_printf (io, "Version: %s%s", PACKAGE_VERSION, CRLF); #if HAVE_DECL_PROGRAM_INVOCATION_NAME - ctlio_printf (io, "Binary:%s%s", program_invocation_name, CRLF); + ctlio_printf (io, "Binary: %s%s", program_invocation_name, CRLF); #endif - ctlio_printf (io, "Instance:%s%s", instance, CRLF); + ctlio_printf (io, "Instance: %s%s", instance, CRLF); ctlio_eot (io); } @@ -327,7 +334,456 @@ cmd_help (struct ctlio *io, size_t argc, char **argv) } ctlio_eot (io); } + +static char const *pies_comp_mode_str[] = { + [pies_comp_exec] = "exec", + [pies_comp_accept] = "accept", + [pies_comp_inetd] = "inetd", + [pies_comp_pass_fd] = "pass_fd", + [pies_comp_wait] = "wait", + [pies_comp_once] = "once", + [pies_comp_boot] = "boot", + [pies_comp_bootwait] = "bootwait", + [pies_comp_powerfail] = "powerfail", + [pies_comp_powerwait] = "powerwait", + [pies_comp_powerokwait] = "powerokwait", + [pies_comp_ctrlaltdel] = "ctrlaltdel", + [pies_comp_ondemand] = "ondemand", + [pies_comp_sysinit] = "sysinit", + [pies_comp_powerfailnow] = "powerfailnow", + [pies_comp_kbrequest] = "kbrequest" +}; + +static char const *status_str[] = { + [status_enabled] = "enabled", + [status_disabled] = "disabled", + [status_listener] = "listener", + [status_sleeping] = "sleeping", + [status_stopping] = "stopping", + [status_finished] = "finished" +}; + +static void +format_idx (struct ctlio *io, const char *header, unsigned i, + char const **a, size_t s) +{ + if (i < s && a[i]) + ctlio_printf (io, "%s: %s%s", header, a[i], CRLF); +} + +#define FORMAT_IDX(io,h,a,i) \ + format_idx (io, h, i, a, sizeof(a)/sizeof(a[0])) + +static int +term_to_idx (char const *str, char const **a, size_t s) +{ + size_t i; + + for (i = 0; i < s; i++) + if (strcasecmp (a[i], str) == 0) + return i; + return -1; +} + +#define TERM_TO_IDX(str,a) term_to_idx (str, a, sizeof (a) / sizeof ((a)[0])) + +/* Prog conditionals */ +enum pcond_type + { + pcond_true, + pcond_component, + 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; + 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 = xmalloc (sizeof (*pn)); + pn->type = t; + return pn; +} + +static int +pcond_eval (struct pcond_node *node, struct prog *p) +{ + if (!node) + return 0; + if (!IS_COMPONENT (p)) + return 0; + switch (node->type) + { + case pcond_true: + return 1; + + case pcond_component: + return strcmp (p->tag, node->v.tag) == 0; + + case pcond_mode: + return p->v.p.comp->mode == node->v.mode; + + case pcond_status: + return 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 void +pcond_free (struct pcond_node *node) +{ + if (!node) + return; + switch (node->type) + { + case pcond_true: + break; + + case pcond_component: + free (node->v.tag); + + case pcond_mode: + case pcond_status: + break; + + case pcond_not: + pcond_free (node->v.unary); + break; + + case pcond_and: + pcond_free (node->v.binary[0]); + pcond_free (node->v.binary[1]); + break; + + case pcond_or: + pcond_free (node->v.binary[0]); + pcond_free (node->v.binary[1]); + break; + + default: + abort (); + } + free (node); +} + +struct pcond_parser_state +{ + struct ctlio *io; + size_t argc; + char **argv; +}; + +static int pcond_parse_binary (struct pcond_parser_state *state, + struct pcond_node **ret); + +static int +pcond_parse_unary (struct pcond_parser_state *state, struct pcond_node **ret) +{ + char *term; + struct pcond_node *pn; + int rc, n; + + if (state->argc == 0) + { + *ret = pcond_node_alloc (pcond_true); + return 0; + } + --state->argc; + term = *state->argv++; + + if (strcasecmp (term, "all") == 0) + pn = pcond_node_alloc (pcond_true); + else if (strcasecmp (term, "mode") == 0) + { + if (!state->argc) + { + ctlio_reply (state->io, "551", "unfinished statement"); + return -1; + } + --state->argc; + term = *state->argv++; + n = TERM_TO_IDX (term, pies_comp_mode_str); + if (n == -1) + { + ctlio_reply (state->io, "551", "undefined mode: %s", term); + return -1; + } + pn = pcond_node_alloc (pcond_mode); + pn->v.mode = n; + } + else if (strcasecmp (term, "status") == 0) + { + if (!state->argc) + { + ctlio_reply (state->io, "551", "unfinished statement"); + return -1; + } + --state->argc; + term = *state->argv++; + n = TERM_TO_IDX (term, status_str); + if (n == -1) + { + ctlio_reply (state->io, "551", "undefined status: %s", term); + return -1; + } + pn = pcond_node_alloc (pcond_status); + pn->v.status = n; + } + else if (strcasecmp (term, "component") == 0) + { + if (!state->argc) + { + ctlio_reply (state->io, "551", "unfinished statement"); + return -1; + } + --state->argc; + term = *state->argv++; + pn = pcond_node_alloc (pcond_component); + pn->v.tag = xstrdup (term); + } + else if (strcasecmp (term, "not") == 0) + { + struct pcond_node *node; + if (!state->argc) + { + ctlio_reply (state->io, "551", "unfinished statement"); + return -1; + } + if (pcond_parse_unary (state, &node) < 0) + return -1; + pn = pcond_node_alloc (pcond_not); + pn->v.unary = node; + } + else if (term[0] == '(') + { + rc = pcond_parse_binary (state, &pn); + if (rc == 0) + { + ctlio_reply (state->io, "551", "unbalanced parethesis"); + return -1; + } + else if (rc == -1) + return rc; + + if (!state->argc || state->argv[0][0] != ')') + { + ctlio_reply (state->io, "551", "unbalanced parethesis"); + pcond_free (pn); + return -1; + } + --state->argc; + ++state->argv; + } + else + { + ctlio_reply (state->io, "551", "parse error near %s", term); + return -1; + } + + *ret = pn; + + return 1; +} + +static int +pcond_parse_binary (struct pcond_parser_state *state, struct pcond_node **ret) +{ + struct pcond_node *pn, *pleft, *pright; + int rc; + char const *term; + int type; + + rc = pcond_parse_unary (state, &pleft); + if (rc < 0) + return rc; + if (state->argc == 0) + { + *ret = pleft; + return 0; + } + + if (state->argv[0][0] == ')') + { + *ret = pleft; + return 1; + } + + --state->argc; + term = *state->argv++; + + if (strcasecmp (term, "and") == 0) + type = pcond_and; + else if (strcasecmp (term, "or") == 0) + type = pcond_or; + else + { + pcond_free (pleft); + ctlio_reply (state->io, "551", "expected 'and' or 'or', but found %s", term); + return -1; + } + + if (state->argc == 0) + { + pcond_free (pleft); + ctlio_reply (state->io, "551", "expected end of statement"); + return -1; + } + + rc = pcond_parse_unary (state, &pright); + if (rc < 0) + { + pcond_free (pleft); + return rc; + } + + pn = pcond_node_alloc (type); + pn->v.binary[0] = pleft; + pn->v.binary[1] = pright; + + *ret = pn; + return 1; +} + +int +pcond_parse (struct ctlio *io, size_t argc, char **argv, + struct pcond_node **pret) +{ + struct pcond_parser_state state = { io, argc, argv }; + int rc; + struct pcond_node *pn; + + rc = pcond_parse_binary (&state, &pn); + if (rc < 0) + return rc; + if (state.argc) + { + pcond_free (pn); + ctlio_reply (io, "551", "trailing garbage at %s", state.argv[0]); + return -1; + } + + *pret = pn; + return 0; +} + +struct eval_env +{ + struct ctlio *io; + struct pcond_node *cond; + size_t count; +}; + +static int +list_prog (struct prog *prog, void *data) +{ + struct eval_env *env = data; + struct ctlio *io = env->io; + size_t i; + + if (!pcond_eval (env->cond, prog)) + return 0; + ctlio_reply (io, "151", "%s", prog->tag); + switch (prog->type) + { + case TYPE_COMPONENT: + FORMAT_IDX (io, "Mode", pies_comp_mode_str, prog->v.p.comp->mode); + FORMAT_IDX (io, "Status", status_str, prog->v.p.status); + + if (prog->pid) + ctlio_printf (io, "PID: %lu%s", (unsigned long) prog->pid, CRLF); + else if (prog->v.p.status == status_listener + && prog->v.p.comp->socket_url) + ctlio_printf (io, "URL: %10s%s", prog->v.p.comp->socket_url->string, CRLF); + +#if 0 + //FIXME + if (prog->v.p.status == status_sleeping) + { + time_t t = prog->v.p.timestamp + SLEEPTIME; + fprintftime (fp, "%H:%M:%S", localtime (&t), 0, 0); + } +#endif + ctlio_printf (io, "Command:"); + for (i = 0; i < prog->v.p.comp->argc; i++) + ctlio_printf (io, " %s", quotearg (prog->v.p.comp->argv[i])); + ctlio_eol (io); + break; + + case TYPE_REDIRECTOR: + ctlio_printf (io, "PID: %10lu%s", (unsigned long) prog->pid, CRLF); + break; + + case TYPE_COMMAND: + ctlio_printf (io, "Command: %s%s", prog->v.c.command, CRLF); + } + ctlio_eot (io); + return 0; +} + +static int +count_prog (struct prog *prog, void *data) +{ + struct eval_env *env = data; + if (pcond_eval (env->cond, prog)) + ++env->count; + return 0; +} + +static void +cmd_list (struct ctlio *io, size_t argc, char **argv) +{ + struct eval_env env; + + env.io = io; + env.count = 0; + if (pcond_parse (io, argc - 1, argv + 1, &env.cond)) + return; + + progman_foreach (count_prog, &env); + if (env.count) + { + ctlio_reply (io, "150", "%lu matches found; list follows", + env.count); + progman_foreach (list_prog, &env); + ctlio_reply (io, "250", "complete"); + } + else + ctlio_reply (io, "552", "No match"); + pcond_free (env.cond); +} static int ctlrd (int fd, void *data); static int ctlwr (int fd, void *data); diff --git a/src/pies.h b/src/pies.h index a4e1a1b..f882f63 100644 --- a/src/pies.h +++ b/src/pies.h @@ -392,7 +392,7 @@ struct pies_url int pies_url_create (struct pies_url **purl, const char *str); void pies_url_destroy (struct pies_url **purl); -const char * pies_url_get_arg (struct pies_url *url, const char *argname); +const char *pies_url_get_arg (struct pies_url *url, const char *argname); void pies_pause (void); diff --git a/src/prog.h b/src/prog.h index 8fddf97..9e55e56 100644 --- a/src/prog.h +++ b/src/prog.h @@ -82,5 +82,7 @@ struct prog } v; }; +#define IS_COMPONENT(p) ((p)->type == TYPE_COMPONENT) + void progman_foreach (int (*filter) (struct prog *, void *data), void *data); void prog_stop (struct prog *prog, int sig); diff --git a/src/progman.c b/src/progman.c index 1455f67..209e211 100644 --- a/src/progman.c +++ b/src/progman.c @@ -17,8 +17,6 @@ #include "pies.h" #include "prog.h" -#define IS_COMPONENT(p) ((p)->type == TYPE_COMPONENT) - static size_t numcomp; static struct prog *proghead, *progtail; static pies_depmap_t depmap; @@ -34,7 +32,7 @@ progman_foreach (int (*filter) (struct prog *, void *data), void *data) break; } -/* FIXME: Rewrite this using progman_foreach */ +/* FIXME: Rewrite this using progman_foreach? */ void progman_iterate_comp (int (*fun) (struct component *, void *), void *data) { diff --git a/src/socket.c b/src/socket.c index 13ee5e0..c94ad4b 100644 --- a/src/socket.c +++ b/src/socket.c @@ -162,6 +162,10 @@ create_socket (struct pies_url *url, int socket_type, const char *host = url->host; short port = url->port; + uid = 0; + gid = 0; + umaskval = 0; + addr.sa.sa_family = PF_INET; socklen = sizeof (addr.s_in); -- cgit v1.2.1