diff --git a/src/Makefile.am b/src/Makefile.am index d3ae9d46..bebd6c14 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,7 +44,7 @@ finit_LDADD += -ldl endif initctl_SOURCES = initctl.c client.c client.h \ - serv.c serv.h svc.c svc.h \ + serv.c serv.h svc.h \ cond.c cond.h util.c util.h initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99 initctl_CFLAGS += $(lite_CFLAGS) diff --git a/src/api.c b/src/api.c index 024883d4..c35e1000 100644 --- a/src/api.c +++ b/src/api.c @@ -21,6 +21,7 @@ * THE SOFTWARE. */ +#include #include #include #include @@ -87,15 +88,42 @@ static int do_start (char *buf, size_t len) { return call(service_start, buf, static int do_stop (char *buf, size_t len) { return call(service_stop, buf, len); } static int do_restart(char *buf, size_t len) { return call(service_restart, buf, len); } -#ifdef INETD_ENABLED -static int do_query_inetd(char *buf, size_t len) +static char query_buf[368]; +static int missing(char *job, int id) +{ + char buf[20]; + char idstr[10] = ""; + + if (!job) + job = ""; + if (id > 1) + snprintf(idstr, sizeof(idstr), ":%d", id); + + snprintf(buf, sizeof(buf), "%s%s ", job, idstr); + strlcat(query_buf, buf, sizeof(query_buf)); + + return 1; +} + +static int do_query(struct init_request *rq, size_t len) +{ + memset(query_buf, 0, sizeof(query_buf)); + if (svc_parse_jobstr(rq->data, strlen(rq->data) + 1, NULL, missing)) { + memcpy(rq->data, query_buf, sizeof(rq->data)); + return 1; + } + + return 0; +} + +static svc_t *do_find(char *buf, size_t len) { int id = 1; - char *ptr, *input = sanitize(buf, len); - svc_t *svc; + char *ptr, *input; + input = sanitize(buf, len); if (!input) - return -1; + return NULL; ptr = strchr(input, ':'); if (ptr) { @@ -103,11 +131,20 @@ static int do_query_inetd(char *buf, size_t len) id = atonum(ptr); } - svc = svc_find_by_jobid(atonum(input), id); - if (!svc || !svc_is_inetd(svc)) { - _e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", input); + if (isdigit(input[0])) + return svc_find_by_jobid(atonum(input), id); + + return svc_find_by_nameid(input, id); +} + +#ifdef INETD_ENABLED +static int do_query_inetd(char *buf, size_t len) +{ + svc_t *svc; + + svc = do_find(buf, len); + if (!svc || !svc_is_inetd(svc)) return 1; - } return inetd_filter_str(&svc->inetd, buf, len); } @@ -164,6 +201,22 @@ static int do_handle_emit(char *buf, size_t len) return result; } +static void send_svc(int sd, svc_t *svc) +{ + svc_t empty; + size_t len; + + if (!svc) { + empty.pid = -1; + svc = ∅ + } + + len = write(sd, svc, sizeof(*svc)); + if (len != sizeof(*svc)) + _d("Failed sending svc_t to client"); +} + + /* * In contrast to the SysV compat handling in plugins/initctl.c, when * `initctl runlevel 0` is issued we default to POWERDOWN the system @@ -290,6 +343,21 @@ static void api_cb(uev_t *w, void *arg, int events) wdogpid = rq.runlevel; break; + case INIT_CMD_SVC_ITER: + _d("svc iter, first: %d", rq.runlevel); + send_svc(sd, svc_iterator(rq.runlevel)); + goto leave; + + case INIT_CMD_SVC_QUERY: + _d("svc query: %s", rq.data); + result = do_query(&rq, len); + break; + + case INIT_CMD_SVC_FIND: + _d("svc find: %s", rq.data); + send_svc(sd, do_find(rq.data, sizeof(rq.data))); + goto leave; + default: _d("Unsupported cmd: %d", rq.cmd); break; diff --git a/src/client.c b/src/client.c index 50e8738e..d5fec8cf 100644 --- a/src/client.c +++ b/src/client.c @@ -89,6 +89,74 @@ exit: return result; } +svc_t *client_svc_iterator(int first) +{ + int sd = -1; + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_SVC_ITER, + }; + static svc_t svc; + + sd = client_connect(); + if (sd == -1) + return NULL; + + if (first) + rq.runlevel = 1; + else + rq.runlevel = 0; + + if (write(sd, &rq, sizeof(rq)) != sizeof(rq)) + goto error; + if (read(sd, &svc, sizeof(svc)) != sizeof(svc)) + goto error; + + client_disconnect(); + if (svc.pid < 0) + return NULL; + + return &svc; +error: + perror("Failed communicating with finit"); + client_disconnect(); + sd = -1; + + return NULL; +} + +svc_t *client_svc_find(char *arg) +{ + int sd = -1; + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_SVC_FIND, + }; + static svc_t svc; + + sd = client_connect(); + if (sd == -1) + return NULL; + + strlcpy(rq.data, arg, sizeof(rq.data)); + if (write(sd, &rq, sizeof(rq)) != sizeof(rq)) + goto error; + if (read(sd, &svc, sizeof(svc)) != sizeof(svc)) + goto error; + + client_disconnect(); + if (svc.pid < 0) + return NULL; + + return &svc; +error: + client_disconnect(); + perror("Failed communicating with finit"); + sd = -1; + + return NULL; +} + /** * Local Variables: * indent-tabs-mode: t diff --git a/src/client.h b/src/client.h index b123af8b..c2e00b6d 100644 --- a/src/client.h +++ b/src/client.h @@ -25,15 +25,18 @@ #define FINIT_CLIENT_H_ #include "finit.h" +#include "svc.h" typedef struct { char *cmd; int (*cb)(char *arg); } command_t; -int client_connect (void); -int client_disconnect (void); +int client_connect (void); +int client_disconnect (void); -int client_send (struct init_request *rq, ssize_t len); +int client_send (struct init_request *rq, ssize_t len); +svc_t *client_svc_iterator (int first); +svc_t *client_svc_find (char *arg); #endif /* FINIT_CLIENT_H_ */ diff --git a/src/finit.h b/src/finit.h index 14e848c9..f60f4ef8 100644 --- a/src/finit.h +++ b/src/finit.h @@ -78,6 +78,9 @@ #define INIT_CMD_EMIT 15 #define INIT_CMD_GET_RUNLEVEL 16 #define INIT_CMD_WDOG_HELLO 128 /* Watchdog register and hello */ +#define INIT_CMD_SVC_ITER 129 +#define INIT_CMD_SVC_QUERY 130 +#define INIT_CMD_SVC_FIND 131 #define INIT_CMD_NACK 254 #define INIT_CMD_ACK 255 diff --git a/src/initctl.c b/src/initctl.c index 85da7acb..6df4ecc0 100644 --- a/src/initctl.c +++ b/src/initctl.c @@ -138,21 +138,6 @@ static int do_svc(int cmd, char *arg) static int do_emit (char *arg) { return do_svc(INIT_CMD_EMIT, arg); } static int do_reload (char *arg) { return do_svc(INIT_CMD_RELOAD, arg); } -static int missing(char *job, int id) -{ - char idstr[10] = ""; - - if (!job) - job = ""; - if (id > 1) - snprintf(idstr, sizeof(idstr), ":%d", id); - - if (verbose) - fprintf(stderr, "No such service %s%s\n", job, idstr); - - return 1; -} - /* * This is a wrapper for do_svc() that adds a simple sanity check of * the service(s) provided as argument. If a service does not exist @@ -160,8 +145,14 @@ static int missing(char *job, int id) */ static int do_startstop(int cmd, char *arg) { - /* Include \0 in len, needed by parser */ - if (svc_parse_jobstr(arg, strlen(arg) + 1, NULL, missing)) { + struct init_request rq = { + .magic = INIT_MAGIC, + .cmd = INIT_CMD_SVC_QUERY + }; + + strlcpy(rq.data, arg, sizeof(rq.data)); + if (client_send(&rq, sizeof(rq))) { + fprintf(stderr, "No such job(s) or service(s): %s\n\n", rq.data); fprintf(stderr, "Usage: initctl %s [:ID]\n", cmd == INIT_CMD_START_SVC ? "start" : (cmd == INIT_CMD_STOP_SVC ? "stop" : "restart")); @@ -257,7 +248,7 @@ static int do_cond_show(char *arg) printheader(NULL, "PID SERVICE STATUS CONDITION (+ ON, ~ FLUX, - OFF)", 0); - for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { + for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) { if (!svc->cond[0]) continue; @@ -420,23 +411,7 @@ static int show_status(char *arg) runlevel = runlevel_get(NULL); if (arg && arg[0]) { - int id = 1; - char *ptr, *next; - - ptr = strchr(arg, ':'); - if (ptr) { - *ptr++ = 0; - next = strchr(ptr, ' '); - if (next) - *next = 0; - id = atonum(ptr); - } - - if (isdigit(arg[0])) - svc = svc_find_by_jobid(atonum(arg), id); - else - svc = svc_find_by_nameid(arg, id); - + svc = client_svc_find(arg); if (!svc) return 1; @@ -447,12 +422,12 @@ static int show_status(char *arg) if (!verbose) printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0); - for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) { + for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) { char jobid[10], args[512] = "", *lvls; - if (svc_is_unique(svc)) - snprintf(jobid, sizeof(jobid), "%d", svc->job); - else +// if (svc_is_unique(svc)) +// snprintf(jobid, sizeof(jobid), "%d", svc->job); +// else snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id); printf("%-5s %7s ", jobid, svc_status(svc));