aboutsummaryrefslogtreecommitdiff
path: root/src/ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ctl.c')
-rw-r--r--src/ctl.c468
1 files changed, 462 insertions, 6 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);

Return to:

Send suggestions and report system problems to the System administrator.