From eb4eac88ebbbae5bf4bc3457b465ed537e6fe917 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Fri, 19 Jul 2024 11:42:53 +0200 Subject: librc-depend.c: split update function into subfunctions in preparation for dynamic service discovery, modularize the dependency tree generation and update into distinct functions. also helps with readability. Signed-off-by: Anna (navi) Figueiredo Gomes --- src/librc/librc-depend.c | 162 ++++++++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 73 deletions(-) diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index 9f592cfe..cb38f190 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -792,38 +792,59 @@ rc_deptree_update_needed(time_t *newest, char *file) return newer; } -/* This is a 7 phase operation - Phase 1 is a shell script which loads each init script and config in turn - and echos their dependency info to stdout - Phase 2 takes that and populates a depinfo object with that data - Phase 3 adds any provided services to the depinfo object - Phase 4 scans that depinfo object and puts in backlinks - Phase 5 removes broken before dependencies - Phase 6 looks for duplicate services indicating a real and virtual service - with the same names - Phase 7 saves the depinfo object to disk - */ -bool -rc_deptree_update(void) +static inline bool +is_nosys(const char *keyword, const char *sys) +{ + return (strncmp(keyword, "no", 2) == 0 && strcasecmp(keyword + 2, sys) == 0) + || (strncmp(keyword, "-", 1) == 0 && strcasecmp(keyword + 1, sys) == 0); +} + +static void +filter_sys(RC_DEPTREE *deptree, const char *sys) { + RC_DEPINFO *depinfo, *depinfo_save, *di; + RC_DEPTYPE *deptype, *provide, *dt, *dt_save; + RC_STRING *s, *s2; + TAILQ_FOREACH_SAFE(depinfo, deptree, entries, depinfo_save) { + if (!(deptype = get_deptype(depinfo, "keyword"))) + continue; + TAILQ_FOREACH(s, deptype->services, entries) { + if (!is_nosys(s->value, sys)) + continue; + provide = get_deptype(depinfo, "iprovide"); + TAILQ_REMOVE(deptree, depinfo, entries); + TAILQ_FOREACH(di, deptree, entries) { + TAILQ_FOREACH_SAFE(dt, &di->depends, entries, dt_save) { + rc_stringlist_delete(dt->services, depinfo->service); + if (provide) + TAILQ_FOREACH(s2, provide->services, entries) + rc_stringlist_delete(dt->services, s2->value); + if (!TAILQ_FIRST(dt->services)) { + TAILQ_REMOVE(&di->depends, dt, entries); + free(dt->type); + free(dt->services); + free(dt); + } + } + } + } + } +} + +static bool +deptree_generate(RC_DEPTREE *deptree, RC_STRINGLIST **config) +{ FILE *fp; - RC_DEPTREE *deptree, *providers; - RC_DEPINFO *depinfo = NULL, *depinfo_np, *di; - RC_DEPTYPE *deptype = NULL, *dt_np, *dt, *provide; - RC_STRINGLIST *config, *dupes, *types, *sorted, *visited; - RC_STRING *s, *s2, *s2_np, *s3, *s4; + RC_DEPTREE *providers; + RC_DEPINFO *depinfo = NULL; + RC_DEPTYPE *deptype = NULL, *dt; char *line = NULL; size_t len = 0; ssize_t size; char *depend, *depends, *service, *type; - char *deptree_cache; - char *depconfig; - size_t i, l; - bool retval = true; const char *sys = rc_sys(); struct utsname uts; - int serrno; /* Some init scripts need RC_LIBEXECDIR to source stuff Ideally we should be setting our full env instead */ @@ -836,10 +857,8 @@ rc_deptree_update(void) if (!(fp = popen(GENDEP, "r"))) return false; - config = rc_stringlist_new(); + *config = rc_stringlist_new(); - deptree = xmalloc(sizeof(*deptree)); - TAILQ_INIT(deptree); while ((size = getline(&line, &len, fp)) != -1) { line[size - 1] = '\0'; depends = line; @@ -871,11 +890,12 @@ rc_deptree_update(void) /* Now add each depend to our type. We do this individually so we handle multiple spaces gracefully */ while ((depend = strsep(&depends, " "))) { + size_t l; if (depend[0] == 0) continue; if (strcmp(type, "config") == 0) { - rc_stringlist_addu(config, depend); + rc_stringlist_addu(*config, depend); continue; } @@ -921,55 +941,15 @@ rc_deptree_update(void) /* Phase 2 - if we're a special system, remove services that don't * work for them. This doesn't stop them from being run directly. */ - if (sys) { - char *nosys, *onosys; - - len = strlen(sys); - nosys = xmalloc(len + 2); - nosys[0] = '-'; - for (i = 0; i < len; i++) - nosys[i + 1] = (char)tolower((unsigned char)sys[i]); - nosys[i + 1] = '\0'; - - onosys = xmalloc(len + 3); - onosys[0] = 'n'; - onosys[1] = 'o'; - for (i = 0; i < len; i++) - onosys[i + 2] = (char)tolower((unsigned char)sys[i]); - onosys[i + 2] = '\0'; - - TAILQ_FOREACH_SAFE(depinfo, deptree, entries, depinfo_np) { - if (!(deptype = get_deptype(depinfo, "keyword"))) - continue; - TAILQ_FOREACH(s, deptype->services, entries) { - if (strcmp(s->value, nosys) != 0 && strcmp(s->value, onosys) != 0) - continue; - provide = get_deptype(depinfo, "iprovide"); - TAILQ_REMOVE(deptree, depinfo, entries); - TAILQ_FOREACH(di, deptree, entries) { - TAILQ_FOREACH_SAFE(dt, &di->depends, entries, dt_np) { - rc_stringlist_delete(dt->services, depinfo->service); - if (provide) - TAILQ_FOREACH(s2, provide->services, entries) - rc_stringlist_delete(dt->services, s2->value); - if (!TAILQ_FIRST(dt->services)) { - TAILQ_REMOVE(&di->depends, dt, entries); - free(dt->type); - free(dt->services); - free(dt); - } - } - } - } - } - free(nosys); - free(onosys); - } + if (sys) + filter_sys(deptree, sys); /* Phase 3 - add our providers to the tree */ providers = xmalloc(sizeof(*providers)); TAILQ_INIT(providers); TAILQ_FOREACH(depinfo, deptree, entries) { + RC_DEPINFO *di; + RC_STRING *s; if (!(deptype = get_deptype(depinfo, "iprovide"))) continue; TAILQ_FOREACH(s, deptype->services, entries) { @@ -981,9 +961,45 @@ rc_deptree_update(void) TAILQ_CONCAT(deptree, providers, entries); free(providers); + return true; +} + +/* This is a 7 phase operation + Phase 1 is a shell script which loads each init script and config in turn + and echos their dependency info to stdout + Phase 2 takes that and populates a depinfo object with that data + Phase 3 adds any provided services to the depinfo object + Phase 4 scans that depinfo object and puts in backlinks + Phase 5 removes broken before dependencies + Phase 6 looks for duplicate services indicating a real and virtual service + with the same names + Phase 7 saves the depinfo object to disk + */ +bool +rc_deptree_update(void) +{ + + FILE *fp; + RC_DEPTREE *deptree; + RC_DEPINFO *depinfo = NULL, *di; + RC_DEPTYPE *deptype = NULL, *dt; + RC_STRINGLIST *config, *dupes, *types, *sorted, *visited; + RC_STRING *s, *s2, *s2_np, *s3, *s4; + char *deptree_cache; + char *depconfig; + bool retval = true; + int serrno; + + deptree = xmalloc(sizeof(*deptree)); + TAILQ_INIT(deptree); + if (!deptree_generate(deptree, &config)) { + free(deptree); + return false; + } + /* Phase 4 - backreference our depends */ TAILQ_FOREACH(depinfo, deptree, entries) { - for (i = 0; deppairs[i].depend; i++) { + for (size_t i = 0; deppairs[i].depend; i++) { deptype = get_deptype(depinfo, deppairs[i].depend); if (!deptype) continue; @@ -1082,7 +1098,7 @@ rc_deptree_update(void) */ xasprintf(&deptree_cache, "%s/%s", rc_service_dir(), RC_DEPTREE_CACHE); if ((fp = fopen(deptree_cache, "w"))) { - i = 0; + size_t i = 0; TAILQ_FOREACH(depinfo, deptree, entries) { fprintf(fp, "depinfo_%zu_service='%s'\n", i, depinfo->service); TAILQ_FOREACH(deptype, &depinfo->depends, entries) { -- cgit v1.2.3