diff --git a/src/conf.c b/src/conf.c index 7ed855f4..b5eeba93 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1011,6 +1011,9 @@ int conf_reload(void) /* Mark any reverse deps as chenaged. */ service_update_rdeps(); + /* Prune according to ifdef:[!]ident */ + service_mark_unavail(); + /* Set up top-level cgroups */ cgroup_config(); done: diff --git a/src/service.c b/src/service.c index 4c84efd9..2a18fbe2 100644 --- a/src/service.c +++ b/src/service.c @@ -1395,6 +1395,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) char *id = NULL, *env = NULL, *cgroup = NULL; char *pre_script = NULL, *post_script = NULL; char *ready_script = NULL, *conflict = NULL; + char *ifdef = NULL, *ifident = NULL; char *notify = NULL; struct tty tty = { 0 }; char *dev = NULL; @@ -1507,6 +1508,10 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) cgroup = arg; /* with group */ else if (MATCH_CMD(cmd, "conflict:", arg)) conflict = arg; + else if (MATCH_CMD(cmd, "if:", arg)) + ifident = arg; + else if (MATCH_CMD(cmd, "ifdef:", arg)) + ifdef = arg; else break; @@ -1520,6 +1525,18 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) if (!id) id = ""; + if (ifident) { + char ident[MAX_IDENT_LEN]; + + if (id[0]) { + snprintf(ident, sizeof(ident), "%s:%s", name, id); + } else + strlcpy(ident, name, sizeof(ident)); + + if (!svc_ifthen(ident, ifident)) + return 0; + } + levels = conf_parse_runlevels(runlevels); if (runlevel > 0 && !ISOTHER(levels, 0)) { dbg("Skipping %s%s%s, bootstrap is completed.", @@ -1710,6 +1727,10 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) strlcpy(svc->conflict, conflict, sizeof(svc->conflict)); else memset(svc->conflict, 0, sizeof(svc->conflict)); + if (ifdef) + strlcpy(svc->ifdef, ifdef, sizeof(svc->ifdef)); + else + memset(svc->ifdef, 0, sizeof(svc->ifdef)); svc->manual = manual; svc->respawn = respawn; svc->forking = forking; @@ -1897,6 +1918,25 @@ void service_update_rdeps(void) } } +/* + * Drop services with 'if:otherserv' if otherserv does not exist. + * Drop services with 'if:!otherserv' if otherserv does exist. + */ +void service_mark_unavail(void) +{ + svc_t *svc, *iter = NULL; + + for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { + char buf[MAX_IDENT_LEN]; + + if (!svc->ifdef[0]) + continue; + + if (!svc_ifthen(svc_ident(svc, buf, sizeof(buf)), svc->ifdef)) + svc_mark(svc); + } +} + static void service_kill_script(svc_t *svc) { if (svc->pid <= 1) diff --git a/src/service.h b/src/service.h index a423d090..cb222618 100644 --- a/src/service.h +++ b/src/service.h @@ -34,6 +34,7 @@ void service_unregister (svc_t *svc); void service_runtask_clean (void); void service_reload_dynamic (void); void service_update_rdeps (void); +void service_mark_unavail (void); void service_ready_script (svc_t *svc); /* XXX: only for pidfile plugin before notify framework */ diff --git a/src/svc.c b/src/svc.c index fb98f847..3e83fb2b 100644 --- a/src/svc.c +++ b/src/svc.c @@ -686,6 +686,32 @@ int svc_conflicts(svc_t *svc) return rc; } +int svc_ifthen(const char *ident, const char *stmt) +{ + int not = 0; + svc_t *svc; + + if (!stmt || !stmt[0]) + return 1; + + if (stmt[0] == '!') { + stmt++; + not++; + } + + svc = svc_find_by_str(stmt); + if (not && svc) { + dbg("skipping %s, %s already loaded.", ident, svc_ident(svc, NULL, 0)); + return 0; + } + if (!not && !svc) { + dbg("skipping %s, %s not available.", ident, stmt); + return 0; + } + + return 1; +} + /* break up "job:id job:id job:id ..." into several "job:id" tokens */ static char *tokstr(char *str, size_t len) { diff --git a/src/svc.h b/src/svc.h index a66621a6..a7eca2b9 100644 --- a/src/svc.h +++ b/src/svc.h @@ -138,6 +138,7 @@ typedef struct svc { int job; /* For intenal use only, canonical ref is NAME:ID */ char name[MAX_ARG_LEN]; char id[MAX_ID_LEN]; /* :ID */ + char ifdef[MAX_IDENT_LEN]; /* Counters */ char once; /* run/task, (at least) once per runlevel */ @@ -237,6 +238,7 @@ void svc_prune_bootstrap (void); void svc_enable (svc_t *svc); int svc_enabled (svc_t *svc); int svc_conflicts (svc_t *svc); +int svc_ifthen (const char *ident, const char *ifstm); int svc_parse_jobstr (char *str, size_t len, void *user_data, int (*found)(svc_t *, void *), int (not_found)(char *, char *, void *));