From f5f1a5574742be353daeb5ceeb5433dbe8e9f374 Mon Sep 17 00:00:00 2001 From: Jonas Johansson Date: Tue, 11 Dec 2018 16:37:25 +0100 Subject: [PATCH] Add support to specify service ID as a string Signed-off-by: Jonas Johansson --- src/api.c | 35 +++++++++++++++++++++++-------- src/finit.c | 2 +- src/inetd.c | 4 +++- src/initctl.c | 4 ++-- src/service.c | 21 ++++++++++++------- src/svc.c | 57 ++++++++++++++++++++++++++++++++------------------- src/svc.h | 16 ++++++++------- 7 files changed, 91 insertions(+), 48 deletions(-) diff --git a/src/api.c b/src/api.c index 1eeaa2c4..5576608d 100644 --- a/src/api.c +++ b/src/api.c @@ -93,17 +93,16 @@ static int do_stop (char *buf, size_t len) { return call(stop, buf, len); } static int do_restart(char *buf, size_t len) { return call(restart, buf, len); } static char query_buf[368]; -static int missing(char *job, int id) +static int missing(char *job, char *id) { char buf[20]; - char idstr[13] = ""; if (!job) job = ""; - if (id > 1) - snprintf(idstr, sizeof(idstr), ":%d", id); + if (!id) + id = ""; - snprintf(buf, sizeof(buf), "%s%s ", job, idstr); + snprintf(buf, sizeof(buf), "%s:%s ", job, id); strlcat(query_buf, buf, sizeof(query_buf)); return 1; @@ -122,8 +121,9 @@ static int do_query(struct init_request *rq, size_t len) static svc_t *do_find(char *buf, size_t len) { - int id = 1; + char *id = NULL; char *ptr, *input; + svc_t *iter = NULL; input = sanitize(buf, len); if (!input) @@ -132,11 +132,28 @@ static svc_t *do_find(char *buf, size_t len) ptr = strchr(input, ':'); if (ptr) { *ptr++ = 0; - id = atonum(ptr); + id = ptr; } - if (isdigit(input[0])) - return svc_find_by_jobid(atonum(input), id); + if (isdigit(input[0])) { + char *ep; + long job = 0; + + errno = 0; + job = strtol(input, &ep, 10); + if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) || + (errno != 0 && job == 0) || + (input == ep)) + return NULL; + + if (!id) + return svc_job_iterator(&iter, 1, job); + + return svc_find_by_jobid(job, id); + } + + if (!id) + return svc_named_iterator(&iter, 1, input); return svc_find_by_nameid(input, id); } diff --git a/src/finit.c b/src/finit.c index aaceae42..b6c5c965 100644 --- a/src/finit.c +++ b/src/finit.c @@ -222,7 +222,7 @@ static void finalize(void) /* * Track bundled watchdogd in case a better one turns up */ - svc = svc_find(FINIT_LIBPATH_ "/watchdogd", 1); + svc = svc_find(FINIT_LIBPATH_ "/watchdogd", "1"); if (svc) wdog = svc; diff --git a/src/inetd.c b/src/inetd.c index 1ef0ecc5..3b6d921c 100644 --- a/src/inetd.c +++ b/src/inetd.c @@ -169,6 +169,7 @@ static void socket_cb(uev_t *w, void *arg, int events) svc_t *svc = (svc_t *)arg, *task; const char *conn = " connection"; char iifname[IF_NAMESIZE + 1] = "UNKNOWN"; + char id[MAX_ID_LEN]; int stdin; _d("%s: Got socket event ...", svc->cmd); @@ -194,7 +195,8 @@ static void socket_cb(uev_t *w, void *arg, int events) return; } - task = svc_new(svc->cmd, svc->inetd.next_id++, SVC_TYPE_INETD_CONN); + snprintf(id, sizeof(id), "%d", svc->inetd.next_id++); + task = svc_new(svc->cmd, id, SVC_TYPE_INETD_CONN); if (!task) { logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd); if (svc->inetd.type == SOCK_STREAM) diff --git a/src/initctl.c b/src/initctl.c index eaf23e78..33a59c16 100644 --- a/src/initctl.c +++ b/src/initctl.c @@ -438,12 +438,12 @@ static int show_status(char *arg) printheader(NULL, "# STATUS PID RUNLEVELS SERVICE DESCRIPTION", 0); for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) { - char jobid[10], args[512] = "", *lvls; + char jobid[20], args[512] = "", *lvls; // if (svc_is_unique(svc)) // snprintf(jobid, sizeof(jobid), "%d", svc->job); // else - snprintf(jobid, sizeof(jobid), "%d:%d", svc->job, svc->id); + snprintf(jobid, sizeof(jobid), "%d:%s", svc->job, svc->id); printf("%-9s %7s ", jobid, svc_status(svc)); if (svc_is_inetd(svc)) diff --git a/src/service.c b/src/service.c index 3bf634a4..f85a20ce 100644 --- a/src/service.c +++ b/src/service.c @@ -672,13 +672,14 @@ static void parse_cmdline_args(svc_t *svc, char *cmd) */ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) { - int id = -1; + char id_str[MAX_ID_LEN]; #ifdef INETD_ENABLED int forking = 0; #endif int levels = 0; int manual = 0; char *line; + char *id = NULL; char *username = NULL, *log = NULL, *pid = NULL; char *service = NULL, *proto = NULL, *ifaces = NULL; char *cmd, *desc, *runlevels = NULL, *cond = NULL; @@ -729,7 +730,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) else if (cmd[0] == '<') /* <[!][cond][,cond..]> */ cond = &cmd[1]; else if (cmd[0] == ':') /* :ID */ - id = atoi(&cmd[1]); + id = &cmd[1]; #ifdef INETD_ENABLED else if (!strncasecmp(cmd, "nowait", 6)) forking = 1; @@ -801,18 +802,24 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) parse_cmdline_args(svc, cmd); goto inetd_setup; } - if (id <= 0) - id = svc_next_id(cmd); + if (!id) { + int n = svc_next_id_int(cmd); + + if (n) { + snprintf(id_str, sizeof(id_str), "%d", n); + id = id_str; + } + } } recreate: #endif - if (id <= 0) - id = 1; + if (!id) + id = "1"; svc = svc_find(cmd, id); if (!svc) { - _d("Creating new svc for %s id #%d type %d", cmd, id, type); + _d("Creating new svc for %s id #%s type %d", cmd, id, type); svc = svc_new(cmd, id, type); if (!svc) { _e("Out of memory, cannot register service %s", cmd); diff --git a/src/svc.c b/src/svc.c index 5a9c4cd5..4769da75 100644 --- a/src/svc.c +++ b/src/svc.c @@ -77,7 +77,7 @@ static void svc_gc(void *arg) * Returns: * A pointer to a new &svc_t object, or %NULL if out of empty slots. */ -svc_t *svc_new(char *cmd, int id, int type) +svc_t *svc_new(char *cmd, char *id, int type) { int job = -1; svc_t *svc, *iter = NULL; @@ -98,7 +98,7 @@ svc_t *svc_new(char *cmd, int id, int type) svc->type = type; svc->job = job; - svc->id = id; + strlcpy(svc->id, id, sizeof(svc->id)); strlcpy(svc->cmd, cmd, sizeof(svc->cmd)); /* Default description, if missing */ @@ -295,12 +295,12 @@ svc_t *svc_stop_completed(void) * Returns: * A pointer to an &svc_t object, or %NULL if not found. */ -svc_t *svc_find(char *cmd, int id) +svc_t *svc_find(char *cmd, char *id) { svc_t *svc, *iter = NULL; for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { - if (svc->id == id && !strncmp(svc->cmd, cmd, strlen(svc->cmd))) + if (svc->id && !strcmp(svc->id, id) && !strncmp(svc->cmd, cmd, strlen(svc->cmd))) return svc; } @@ -334,12 +334,12 @@ svc_t *svc_find_by_pid(pid_t pid) * Returns: * A pointer to an &svc_t object, or %NULL if not found. */ -svc_t *svc_find_by_jobid(int job, int id) +svc_t *svc_find_by_jobid(int job, char *id) { svc_t *svc, *iter = NULL; for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { - if (svc->job == job && svc->id == id) + if (svc->job == job && svc->id && !strcmp(svc->id, id)) return svc; } @@ -354,12 +354,12 @@ svc_t *svc_find_by_jobid(int job, int id) * Returns: * A pointer to an &svc_t object, or %NULL if not found. */ -svc_t *svc_find_by_nameid(char *name, int id) +svc_t *svc_find_by_nameid(char *name, char *id) { svc_t *svc, *iter = NULL; for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { - if (svc->id == id && !strcmp(name, svc->name)) + if (svc->id && !strcmp(svc->id, id) && !strcmp(name, svc->name)) return svc; } @@ -496,18 +496,24 @@ int svc_enabled(svc_t *svc) return 1; } -/* Same base service, return unique ID */ -int svc_next_id(char *cmd) +/* Same base service, return unique ID as an integer */ +int svc_next_id_int(char *cmd) { - int id = 0; + int n = 1; svc_t *svc, *iter = NULL; for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { - if (!strcmp(svc->cmd, cmd) && id < svc->id) - id = svc->id; + char id[MAX_ID_LEN]; + + snprintf(id, sizeof(id), "%d", n); + + if (!strcmp(svc->cmd, cmd) && svc->id && strcmp(svc->id, id)) + return n; + + n++; } - return id + 1; + return 0; } int svc_is_unique(svc_t *svc) @@ -534,7 +540,7 @@ int svc_is_unique(svc_t *svc) /* * Used by api.c (to start/stop/restart) and initctl.c (for input validation) */ -int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int)) +int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *)) { int result = 0; char *input, *token, *pos; @@ -545,17 +551,27 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun token = strtok_r(input, " ", &pos); while (token) { - int id = 1; + char *id = NULL; svc_t *svc, *iter = NULL; char *ptr = strchr(token, ':'); if (isdigit(token[0])) { - int job = atonum(token); + char *ep; + long job = 0; + + errno = 0; + job = strtol(token, &ep, 10); + if ((errno == ERANGE && (job == LONG_MAX || job == LONG_MIN)) || + (errno != 0 && job == 0) || + (token == ep)) { + result++; + continue; + } if (!ptr) { svc = svc_job_iterator(&iter, 1, job); if (!svc && not_found) - result += not_found(NULL, job); + result += not_found(NULL, token); while (svc) { if (found) @@ -564,8 +580,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun } } else { *ptr++ = 0; - id = atonum(ptr); - job = atonum(token); + id = ptr; svc = svc_find_by_jobid(job, id); if (!svc && not_found) @@ -586,7 +601,7 @@ int svc_parse_jobstr(char *str, size_t len, int (*found)(svc_t *), int (not_foun } } else { *ptr++ = 0; - id = atonum(ptr); + id = ptr; svc = svc_find_by_nameid(token, id); if (!svc && not_found) diff --git a/src/svc.h b/src/svc.h index 453dea67..ae539fde 100644 --- a/src/svc.h +++ b/src/svc.h @@ -66,6 +66,7 @@ typedef enum { SVC_BLOCK_RESTARTING, } svc_block_t; +#define MAX_ID_LEN 16 #define MAX_ARG_LEN 64 #define MAX_STR_LEN 64 #define MAX_COND_LEN (MAX_ARG_LEN * 3) @@ -86,7 +87,8 @@ typedef struct svc { TAILQ_ENTRY(svc) link; /* Instance specifics */ - int job, id; /* JOB:ID */ + int job; /* JOB: */ + char id[MAX_ID_LEN]; /* :ID */ /* Limits and scoping */ struct rlimit rlimit[RLIMIT_NLIMITS]; @@ -145,13 +147,13 @@ typedef struct svc { struct timespec gc; } svc_t; -svc_t *svc_new (char *cmd, int id, int type); +svc_t *svc_new (char *cmd, char *id, int type); int svc_del (svc_t *svc); -svc_t *svc_find (char *cmd, int id); +svc_t *svc_find (char *cmd, char *id); svc_t *svc_find_by_pid (pid_t pid); -svc_t *svc_find_by_jobid (int job, int id); -svc_t *svc_find_by_nameid (char *name, int id); +svc_t *svc_find_by_jobid (int job, char *id); +svc_t *svc_find_by_nameid (char *name, char *id); svc_t *svc_find_by_pidfile (char *fn); svc_t *svc_iterator (svc_t **iter, int first); @@ -172,10 +174,10 @@ int svc_clean_bootstrap (svc_t *svc); void svc_prune_bootstrap (void); int svc_enabled (svc_t *svc); -int svc_next_id (char *cmd); +int svc_next_id_int (char *cmd); int svc_is_unique (svc_t *svc); -int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, int)); +int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *)); static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; } static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }