diff options
Diffstat (limited to 'src/librc/librc-depend.c')
-rw-r--r-- | src/librc/librc-depend.c | 1012 |
1 files changed, 447 insertions, 565 deletions
diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index 22470368..8617d753 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -37,31 +37,18 @@ static const char *bootlevel = NULL; -/* We use this so we can pass our char array through many functions */ -struct lhead -{ - char **list; -}; - -static void *xzalloc (size_t size) -{ - void *value = xmalloc (size); - memset (value, 0, size); - return (value); -} - -static char *get_shell_value (char *string) +static char *get_shell_value(char *string) { char *p = string; char *e; if (! string) - return (NULL); + return NULL; if (*p == '\'') p++; - e = p + strlen (p) - 1; + e = p + strlen(p) - 1; if (*e == '\n') *e-- = 0; if (*e == '\'') @@ -70,191 +57,184 @@ static char *get_shell_value (char *string) if (*p != 0) return p; - return (NULL); + return NULL; } -void rc_deptree_free (rc_depinfo_t *deptree) +void rc_deptree_free(RC_DEPTREE *deptree) { - rc_depinfo_t *di = deptree; + RC_DEPINFO *di; + RC_DEPINFO *di2; + RC_DEPTYPE *dt; + RC_DEPTYPE *dt2; + + if (! deptree) + return; + + di = STAILQ_FIRST(deptree); while (di) { - rc_depinfo_t *dip = di->next; - rc_deptype_t *dt = di->depends; - free (di->service); + di2 = STAILQ_NEXT(di, entries); + dt = STAILQ_FIRST(&di->depends); while (dt) { - rc_deptype_t *dtp = dt->next; - free (dt->type); - rc_strlist_free (dt->services); - free (dt); - dt = dtp; + dt2 = STAILQ_NEXT(dt, entries); + rc_stringlist_free(dt->services); + free(dt->type); + free(dt); + dt = dt2; } - free (di); - di = dip; + free(di->service); + free(di); + di = di2; } + free(deptree); } librc_hidden_def(rc_deptree_free) -static rc_depinfo_t *get_depinfo (const rc_depinfo_t *deptree, - const char *service) +static RC_DEPINFO *get_depinfo(const RC_DEPTREE *deptree, + const char *service) { - const rc_depinfo_t *di; - - if (! deptree || ! service) - return (NULL); + RC_DEPINFO *di; - for (di = deptree; di; di = di->next) - if (strcmp (di->service, service) == 0) - return ((rc_depinfo_t *)di); + STAILQ_FOREACH(di, deptree, entries) + if (strcmp(di->service, service) == 0) + return di; - return (NULL); + return NULL; } -static rc_deptype_t *get_deptype (const rc_depinfo_t *depinfo, - const char *type) +static RC_DEPTYPE *get_deptype(const RC_DEPINFO *depinfo, + const char *type) { - rc_deptype_t *dt; + RC_DEPTYPE *dt; - if (! depinfo || !type) - return (NULL); + STAILQ_FOREACH(dt, &depinfo->depends, entries) + if (strcmp(dt->type, type) == 0) + return dt; - for (dt = depinfo->depends; dt; dt = dt->next) - if (strcmp (dt->type, type) == 0) - return (dt); - - return (NULL); + return NULL; } -rc_depinfo_t *rc_deptree_load (void) +RC_DEPTREE *rc_deptree_load(void) { FILE *fp; - rc_depinfo_t *deptree = NULL; - rc_depinfo_t *depinfo = NULL; - rc_deptype_t *deptype = NULL; + RC_DEPTREE *deptree; + RC_DEPINFO *depinfo = NULL; + RC_DEPTYPE *deptype = NULL; char *line; char *type; char *p; char *e; int i; - if (! (fp = fopen (RC_DEPTREE, "r"))) - return (NULL); + if (!(fp = fopen(RC_DEPTREE_CACHE, "r"))) + return NULL; + + deptree = xmalloc(sizeof(*deptree)); + STAILQ_INIT(deptree); - while ((line = rc_getline (fp))) + while ((line = rc_getline(fp))) { p = line; - e = strsep (&p, "_"); - if (! e || strcmp (e, "depinfo") != 0) + e = strsep(&p, "_"); + if (! e || strcmp(e, "depinfo") != 0) goto next; e = strsep (&p, "_"); - if (! e || sscanf (e, "%d", &i) != 1) + if (! e || sscanf(e, "%d", &i) != 1) goto next; - if (! (type = strsep (&p, "_="))) + if (! (type = strsep(&p, "_="))) goto next; - if (strcmp (type, "service") == 0) + if (strcmp(type, "service") == 0) { /* Sanity */ - e = get_shell_value (p); + e = get_shell_value(p); if (! e || *e == '\0') goto next; - if (! deptree) - { - deptree = xzalloc (sizeof (*deptree)); - depinfo = deptree; - } - else - { - depinfo->next = xzalloc (sizeof (*depinfo->next)); - depinfo = depinfo->next; - } - depinfo->service = xstrdup (e); + depinfo = xmalloc(sizeof(*depinfo)); + STAILQ_INIT(&depinfo->depends); + depinfo->service = xstrdup(e); + STAILQ_INSERT_TAIL(deptree, depinfo, entries); deptype = NULL; goto next; } - e = strsep (&p, "="); - if (! e || sscanf (e, "%d", &i) != 1) + e = strsep(&p, "="); + if (! e || sscanf(e, "%d", &i) != 1) goto next; /* Sanity */ - e = get_shell_value (p); + e = get_shell_value(p); if (! e || *e == '\0') goto next; - if (! deptype) - { - depinfo->depends = xzalloc (sizeof (*depinfo->depends)); - deptype = depinfo->depends; - } - else - if (strcmp (deptype->type, type) != 0) - { - deptype->next = xzalloc (sizeof (*deptype->next)); - deptype = deptype->next; - } - - if (! deptype->type) + if (! deptype || strcmp(deptype->type, type) != 0) { + deptype = xmalloc(sizeof(*deptype)); + deptype->services = rc_stringlist_new(); deptype->type = xstrdup (type); + STAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); + } - rc_strlist_addsort (&deptype->services, e); - + rc_stringlist_add(deptype->services, e); next: - free (line); + free(line); } - fclose (fp); - - return (deptree); + fclose(fp); + + return deptree; } librc_hidden_def(rc_deptree_load) -static bool valid_service (const char *runlevel, const char *service) +static bool valid_service(const char *runlevel, const char *service) { - rc_service_state_t state = rc_service_state (service); + RC_SERVICE state = rc_service_state(service); return ((strcmp (runlevel, bootlevel) != 0 && - rc_service_in_runlevel (service, bootlevel)) || - rc_service_in_runlevel (service, runlevel) || + rc_service_in_runlevel(service, bootlevel)) || + rc_service_in_runlevel(service, runlevel) || state & RC_SERVICE_COLDPLUGGED || state & RC_SERVICE_STARTED); } -static bool get_provided1 (const char *runlevel, struct lhead *providers, - rc_deptype_t *deptype, - const char *level, bool coldplugged, - rc_service_state_t state) +static bool get_provided1(const char *runlevel, RC_STRINGLIST *providers, + RC_DEPTYPE *deptype, + const char *level, bool coldplugged, + RC_SERVICE state) { - char *service; - int i; + RC_STRING *service; + RC_SERVICE st; bool retval = false; + bool ok; + const char *svc; + + TAILQ_FOREACH(service, deptype->services, entries) { + ok = true; + svc = service->value; + st = rc_service_state(svc); - STRLIST_FOREACH (deptype->services, service, i) - { - bool ok = true; - rc_service_state_t s = rc_service_state (service); if (level) - ok = rc_service_in_runlevel (service, level); + ok = rc_service_in_runlevel(svc, level); else if (coldplugged) - ok = (s & RC_SERVICE_COLDPLUGGED && - ! rc_service_in_runlevel (service, runlevel) && - ! rc_service_in_runlevel (service, bootlevel)); + ok = (st & RC_SERVICE_COLDPLUGGED && + ! rc_service_in_runlevel(svc, runlevel) && + ! rc_service_in_runlevel(svc, bootlevel)); if (! ok) continue; switch (state) { case RC_SERVICE_STARTED: - ok = (s & RC_SERVICE_STARTED); + ok = (st & RC_SERVICE_STARTED); break; case RC_SERVICE_INACTIVE: case RC_SERVICE_STARTING: case RC_SERVICE_STOPPING: - ok = (s & RC_SERVICE_STARTING || - s & RC_SERVICE_STOPPING || - s & RC_SERVICE_INACTIVE); + ok = (st & RC_SERVICE_STARTING || + st & RC_SERVICE_STOPPING || + st & RC_SERVICE_INACTIVE); break; default: break; @@ -264,10 +244,10 @@ static bool get_provided1 (const char *runlevel, struct lhead *providers, continue; retval = true; - rc_strlist_add (&providers->list, service); + rc_stringlist_add(providers, svc); } - return (retval); + return retval; } /* Work out if a service is provided by another service. @@ -279,50 +259,41 @@ static bool get_provided1 (const char *runlevel, struct lhead *providers, If there are any bugs in rc-depend, they will probably be here as provided dependancy can change depending on runlevel state. */ -static char **get_provided (const rc_depinfo_t *deptree, - const rc_depinfo_t *depinfo, - const char *runlevel, int options) +static RC_STRINGLIST *get_provided (const RC_DEPINFO *depinfo, + const char *runlevel, int options) { - rc_deptype_t *dt; - struct lhead providers; - char *service; - int i; + RC_DEPTYPE *dt; + RC_STRINGLIST *providers = rc_stringlist_new(); + RC_STRING *service; - if (! deptree || ! depinfo) - return (NULL); - - if (rc_service_exists (depinfo->service)) - return (NULL); - - dt = get_deptype (depinfo, "providedby"); + dt = get_deptype(depinfo, "providedby"); if (! dt) - return (NULL); + return providers; - memset (&providers, 0, sizeof (providers)); /* If we are stopping then all depends are true, regardless of state. This is especially true for net services as they could force a restart of the local dns resolver which may depend on net. */ if (options & RC_DEP_STOP) { - STRLIST_FOREACH (dt->services, service, i) - rc_strlist_add (&providers.list, service); - - return (providers.list); + TAILQ_FOREACH(service, dt->services, entries) + rc_stringlist_add(providers, service->value); + return providers; } /* If we're strict or startng, then only use what we have in our * runlevel and bootlevel. If we starting then check cold-plugged too. */ if (options & RC_DEP_STRICT || options & RC_DEP_START) { - STRLIST_FOREACH (dt->services, service, i) - if (rc_service_in_runlevel (service, runlevel) || - rc_service_in_runlevel (service, bootlevel) || + + TAILQ_FOREACH(service, dt->services, entries) + if (rc_service_in_runlevel(service->value, runlevel) || + rc_service_in_runlevel(service->value, bootlevel) || (options & RC_DEP_START && - rc_service_state (service) & RC_SERVICE_COLDPLUGGED)) - rc_strlist_add (&providers.list, service); + rc_service_state(service->value) & RC_SERVICE_COLDPLUGGED)) + rc_stringlist_add(providers, service->value); - if (providers.list) - return (providers.list); + if (TAILQ_FIRST(providers)) + return providers; } /* OK, we're not strict or there were no services in our runlevel. @@ -333,225 +304,211 @@ static char **get_provided (const rc_depinfo_t *deptree, We apply this to our runlevel, coldplugged services, then bootlevel and finally any running.*/ #define DO \ - if (providers.list && providers.list[0] && providers.list[1]) \ - { \ - rc_strlist_free (providers.list); \ - return (NULL); \ - } \ - else if (providers.list) \ - return providers.list; \ + if (TAILQ_FIRST(providers)) { \ + if (TAILQ_NEXT(TAILQ_FIRST(providers), entries)) { \ + rc_stringlist_free(providers); \ + providers = rc_stringlist_new(); \ + } \ + return providers; \ + } /* Anything in the runlevel has to come first */ - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STARTING)) - return (providers.list); - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STOPPED)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STARTING)) + return providers; + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED)) + return providers; /* Check coldplugged services */ - if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STARTING)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STARTING)) + return providers; /* Check bootlevel if we're not in it */ if (bootlevel && strcmp (runlevel, bootlevel) != 0) { - if (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STARTING)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STARTING)) + return providers; } /* Check coldplugged services */ - if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STOPPED)) + if (get_provided1 (runlevel, providers, dt, NULL, true, RC_SERVICE_STOPPED)) { DO } /* Check manually started */ - if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTED)) + if (get_provided1 (runlevel, providers, dt, NULL, false, RC_SERVICE_STARTED)) { DO } - if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTING)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, NULL, false, RC_SERVICE_STARTING)) + return providers; /* Nothing started then. OK, lets get the stopped services */ - if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STOPPED)) - return (providers.list); + if (get_provided1 (runlevel, providers, dt, runlevel, false, RC_SERVICE_STOPPED)) + return providers; if (bootlevel && (strcmp (runlevel, bootlevel) != 0) - && (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STOPPED))) - return (providers.list); + && (get_provided1 (runlevel, providers, dt, bootlevel, false, RC_SERVICE_STOPPED))) + return providers; /* Still nothing? OK, list all services */ - STRLIST_FOREACH (dt->services, service, i) - rc_strlist_add (&providers.list, service); + TAILQ_FOREACH(service, dt->services, entries) + rc_stringlist_add(providers, service->value); - return (providers.list); + return providers; } -static void visit_service (const rc_depinfo_t *deptree, - const char * const *types, - struct lhead *sorted, struct lhead *visited, - const rc_depinfo_t *depinfo, +static void visit_service (const RC_DEPTREE *deptree, + const RC_STRINGLIST *types, + RC_STRINGLIST *sorted, + RC_STRINGLIST *visited, + const RC_DEPINFO *depinfo, const char *runlevel, int options) { - int i, j, k; - char *lp; - const char *item; - char *service; - rc_depinfo_t *di; - rc_deptype_t *dt; - char **provides; - char *svcname; - - if (! deptree || !sorted || !visited || !depinfo) - return; + RC_STRING *type; + RC_STRING *service; + RC_DEPTYPE *dt; + RC_DEPINFO *di; + RC_STRINGLIST *provided; + RC_STRING *p; + const char *svcname; /* Check if we have already visited this service or not */ - STRLIST_FOREACH (visited->list, item, i) - if (strcmp (item, depinfo->service) == 0) + TAILQ_FOREACH(type, visited, entries) + if (strcmp(type->value, depinfo->service) == 0) return; /* Add ourselves as a visited service */ - rc_strlist_add (&visited->list, depinfo->service); + rc_stringlist_add(visited, depinfo->service); - STRLIST_FOREACH (types, item, i) + TAILQ_FOREACH(type, types, entries) { - if ((dt = get_deptype (depinfo, item))) - { - STRLIST_FOREACH (dt->services, service, j) + if (!(dt = get_deptype(depinfo, type->value))) + continue; + + TAILQ_FOREACH(service, dt->services, entries) { + if (! options & RC_DEP_TRACE || + strcmp(type->value, "iprovide") == 0) { - if (! options & RC_DEP_TRACE || strcmp (item, "iprovide") == 0) - { - rc_strlist_add (&sorted->list, service); - continue; - } + rc_stringlist_add(sorted, service->value); + continue; + } - di = get_depinfo (deptree, service); - if ((provides = get_provided (deptree, di, runlevel, options))) - { - STRLIST_FOREACH (provides, lp, k) - { - di = get_depinfo (deptree, lp); - if (di && (strcmp (item, "ineed") == 0 || - strcmp (item, "needsme") == 0 || - valid_service (runlevel, di->service))) - visit_service (deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - } - rc_strlist_free (provides); + if (!(di = get_depinfo(deptree, service->value))) + continue; + provided = get_provided(di, runlevel, options); + + if (TAILQ_FIRST(provided)) { + TAILQ_FOREACH(p, provided, entries) { + di = get_depinfo(deptree, p->value); + if (di && + (strcmp(type->value, "ineed") == 0 || + strcmp(type->value, "needsme") == 0 || + valid_service(runlevel, di->service))) + visit_service(deptree, types, sorted, visited, di, + runlevel, options | RC_DEP_TRACE); } - else - if (di && (strcmp (item, "ineed") == 0 || - strcmp (item, "needsme") == 0 || - valid_service (runlevel, service))) - visit_service (deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); } + else if (di && + (strcmp(type->value, "ineed") == 0 || + strcmp(type->value, "needsme") == 0 || + valid_service(runlevel, service->value))) + visit_service(deptree, types, sorted, visited, di, + runlevel, options | RC_DEP_TRACE); + + rc_stringlist_free(provided); } } /* Now visit the stuff we provide for */ if (options & RC_DEP_TRACE && - (dt = get_deptype (depinfo, "iprovide"))) + (dt = get_deptype(depinfo, "iprovide"))) { - STRLIST_FOREACH (dt->services, service, i) - { - if ((di = get_depinfo (deptree, service))) - if ((provides = get_provided (deptree, di, runlevel, options))) - { - STRLIST_FOREACH (provides, lp, j) - if (strcmp (lp, depinfo->service) == 0) - { - visit_service (deptree, types, sorted, visited, di, - runlevel, options | RC_DEP_TRACE); - break; - } - rc_strlist_free (provides); + TAILQ_FOREACH(service, dt->services, entries) { + if (!(di = get_depinfo(deptree, service->value))) + continue; + + provided = get_provided(di, runlevel, options); + TAILQ_FOREACH(p, provided, entries) + if (strcmp (p->value, depinfo->service) == 0) { + //visit_service (deptree, types, sorted, visited, di, + // runlevel, options | RC_DEP_TRACE); + break; } + rc_stringlist_free(provided); } } /* We've visited everything we need, so add ourselves unless we are also the service calling us or we are provided by something */ svcname = getenv("SVCNAME"); - if (! svcname || strcmp (svcname, depinfo->service) != 0) - if (! get_deptype (depinfo, "providedby")) - rc_strlist_add (&sorted->list, depinfo->service); + if (! svcname || strcmp(svcname, depinfo->service) != 0) + if (! get_deptype(depinfo, "providedby")) + rc_stringlist_add(sorted, depinfo->service); } -char **rc_deptree_depend (const rc_depinfo_t *deptree, - const char *service, const char *type) +RC_STRINGLIST *rc_deptree_depend(const RC_DEPTREE *deptree, + const char *service, const char *type) { - rc_depinfo_t *di; - rc_deptype_t *dt; - char **svcs = NULL; - int i; - char *svc; + RC_DEPINFO *di; + RC_DEPTYPE *dt; + RC_STRINGLIST *svcs; + RC_STRING *svc; - if (! (di = get_depinfo (deptree, service)) || - ! (dt = get_deptype (di, type))) + if (!(di = get_depinfo(deptree, service)) || + ! (dt = get_deptype(di, type))) { errno = ENOENT; - return (NULL); + return NULL; } /* For consistency, we copy the array */ - STRLIST_FOREACH (dt->services, svc, i) - rc_strlist_add (&svcs, svc); + svcs = rc_stringlist_new(); + TAILQ_FOREACH(svc, dt->services, entries) + rc_stringlist_add(svcs, svc->value); - return (svcs); + return svcs; } librc_hidden_def(rc_deptree_depend) -char **rc_deptree_depends (const rc_depinfo_t *deptree, - const char *const *types, - const char *const *services, - const char *runlevel, int options) +RC_STRINGLIST *rc_deptree_depends (const RC_DEPTREE *deptree, + const RC_STRINGLIST *types, + const RC_STRINGLIST *services, + const char *runlevel, int options) { - struct lhead sorted; - struct lhead visited; - rc_depinfo_t *di; - const char *service; - int i; - - if (! deptree || ! services) - return (NULL); - - memset (&sorted, 0, sizeof (sorted)); - memset (&visited, 0, sizeof (visited)); + RC_STRINGLIST *sorted = rc_stringlist_new(); + RC_STRINGLIST *visited = rc_stringlist_new(); + RC_DEPINFO *di; + const RC_STRING *service; bootlevel = getenv ("RC_BOOTLEVEL"); if (! bootlevel) bootlevel = RC_LEVEL_BOOT; - STRLIST_FOREACH (services, service, i) - { - if (! (di = get_depinfo (deptree, service))) { + TAILQ_FOREACH(service, services, entries) { + if (! (di = get_depinfo(deptree, service->value))) { errno = ENOENT; continue; } if (types) - visit_service (deptree, types, &sorted, &visited, + visit_service (deptree, types, sorted, visited, di, runlevel, options); } - rc_strlist_free (visited.list); - return (sorted.list); + rc_stringlist_free (visited); + return sorted; } librc_hidden_def(rc_deptree_depends) - static const char * const order_types[] = { "ineed", "iuse", "iafter", NULL }; -char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel, - int options) +RC_STRINGLIST *rc_deptree_order(const RC_DEPTREE *deptree, + const char *runlevel, int options) { - char **list = NULL; - char **services = NULL; - bool reverse = false; - char **tmp = NULL; - - if (! runlevel) - return (NULL); + RC_STRINGLIST *list; + RC_STRINGLIST *list2; + RC_STRINGLIST *types; + RC_STRINGLIST *services; bootlevel = getenv ("RC_BOOTLEVEL"); if (! bootlevel) @@ -562,47 +519,48 @@ char **rc_deptree_order (const rc_depinfo_t *deptree, const char *runlevel, strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 || strcmp (runlevel, RC_LEVEL_REBOOT) == 0) { - list = rc_services_in_state (RC_SERVICE_STARTED); + list = rc_services_in_state(RC_SERVICE_STARTED); - tmp = rc_services_in_state (RC_SERVICE_INACTIVE); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); + list2 = rc_services_in_state (RC_SERVICE_INACTIVE); + TAILQ_CONCAT(list, list2); + free(list2); - tmp = rc_services_in_state (RC_SERVICE_STARTING); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); - reverse = true; + list2 = rc_services_in_state (RC_SERVICE_STARTING); + TAILQ_CONCAT(list, list2); + free(list2); } else { list = rc_services_in_runlevel (runlevel); /* Add coldplugged services */ - tmp = rc_services_in_state (RC_SERVICE_COLDPLUGGED); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); + list2 = rc_services_in_state (RC_SERVICE_COLDPLUGGED); + TAILQ_CONCAT(list, list2); + free(list2); /* If we're not the boot runlevel then add that too */ if (strcmp (runlevel, bootlevel) != 0) { - tmp = rc_services_in_runlevel (bootlevel); - rc_strlist_join (&list, tmp); - rc_strlist_free (tmp); + list2 = rc_services_in_runlevel (bootlevel); + TAILQ_CONCAT(list, list2); + free(list2); } } /* Now we have our lists, we need to pull in any dependencies and order them */ - services = rc_deptree_depends (deptree, order_types, (const char **) list, - runlevel, - RC_DEP_STRICT | RC_DEP_TRACE | options); - rc_strlist_free (list); + types = rc_stringlist_new(); + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iuse"); + rc_stringlist_add(types, "iafter"); - if (reverse) - rc_strlist_reverse (services); + services = rc_deptree_depends(deptree, types, list, runlevel, + RC_DEP_STRICT | RC_DEP_TRACE | options); + rc_stringlist_free (list); + rc_stringlist_free (types); - return (services); + return services; } librc_hidden_def(rc_deptree_order) -bool rc_newer_than (const char *source, const char *target) +bool rc_newer_than(const char *source, const char *target) { struct stat buf; time_t mtime; @@ -613,38 +571,38 @@ bool rc_newer_than (const char *source, const char *target) int serrno = errno; /* We have to exist */ - if (stat (source, &buf) != 0) - return (false); + if (stat(source, &buf) != 0) + return false; mtime = buf.st_mtime; /* Of course we are newer than targets that don't exist such as broken symlinks */ - if (stat (target, &buf) != 0) - return (true); + if (stat(target, &buf) != 0) + return true; if (mtime < buf.st_mtime) - return (false); + return false; /* If not a dir then reset errno */ - if (! (dp = opendir (target))) { + if (! (dp = opendir(target))) { errno = serrno; - return (true); + return true; } /* Check if we're newer than all the entries in the dir */ - while ((d = readdir (dp))) { + while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; - path = rc_strcatpaths (target, d->d_name, (char *) NULL); - newer = rc_newer_than (source, path); - free (path); + path = rc_strcatpaths(target, d->d_name, (char *) NULL); + newer = rc_newer_than(source, path); + free(path); if (! newer) break; } - closedir (dp); + closedir(dp); - return (newer); + return newer; } librc_hidden_def(rc_newer_than) @@ -652,12 +610,12 @@ typedef struct deppair { const char *depend; const char *addto; -} deppair_t; +} DEPPAIR; -static const deppair_t deppairs[] = { - { "ineed", "needsme" }, - { "iuse", "usesme" }, - { "iafter", "ibefore" }, +static const DEPPAIR deppairs[] = { + { "ineed", "needsme" }, + { "iuse", "usesme" }, + { "iafter", "ibefore" }, { "ibefore", "iafter" }, { "iprovide", "providedby" }, { NULL, NULL } @@ -679,168 +637,151 @@ static const char *const depdirs[] = NULL }; -bool rc_deptree_update_needed (void) +bool rc_deptree_update_needed(void) { bool newer = false; - char **config; - char *service; + RC_STRINGLIST *config; + RC_STRING *s; int i; /* Create base directories if needed */ for (i = 0; depdirs[i]; i++) - if (mkdir (depdirs[i], 0755) != 0 && errno != EEXIST) - fprintf (stderr, "mkdir `%s': %s\n", depdirs[i], strerror (errno)); + if (mkdir(depdirs[i], 0755) != 0 && errno != EEXIST) + fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror (errno)); /* Quick test to see if anything we use has changed and we have * data in our deptree */ - if (! existss (RC_DEPTREE) || - ! rc_newer_than (RC_DEPTREE, RC_INITDIR) || - ! rc_newer_than (RC_DEPTREE, RC_CONFDIR) || + if (! existss(RC_DEPTREE_CACHE) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR) || #ifdef RC_PKG_INITDIR - ! rc_newer_than (RC_DEPTREE, RC_PKG_INITDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR) || #endif #ifdef RC_PKG_CONFDIR - ! rc_newer_than (RC_DEPTREE, RC_PKG_CONFDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR) || #endif #ifdef RC_LOCAL_INITDIR - ! rc_newer_than (RC_DEPTREE, RC_LOCAL_INITDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR) || #endif #ifdef RC_LOCAL_CONFDIR - ! rc_newer_than (RC_DEPTREE, RC_LOCAL_CONFDIR) || + ! rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR) || #endif - ! rc_newer_than (RC_DEPTREE, "/etc/rc.conf")) - return (true); + ! rc_newer_than(RC_DEPTREE_CACHE, "/etc/rc.conf")) + return true; /* Some init scripts dependencies change depending on config files * outside of baselayout, like syslog-ng, so we check those too. */ config = rc_config_list (RC_DEPCONFIG); - STRLIST_FOREACH (config, service, i) { - if (! rc_newer_than (RC_DEPTREE, service)) { + TAILQ_FOREACH(s, config, entries) { + if (! rc_newer_than(RC_DEPTREE_CACHE, s->value)) { newer = true; break; } } - rc_strlist_free (config); + rc_stringlist_free(config); - return (newer); + return newer; } librc_hidden_def(rc_deptree_update_needed) - /* This is a 5 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 saves the depinfo object to disk - */ -bool rc_deptree_update (void) +/* This is a 5 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 saves the depinfo object to disk + */ +bool rc_deptree_update(void) { + FILE *fp; + RC_DEPTREE *deptree; + RC_DEPTREE *providers; + RC_DEPINFO *depinfo = NULL; + RC_DEPINFO *depinfo_np; + RC_DEPINFO *di; + RC_DEPTYPE *deptype = NULL; + RC_DEPTYPE *dt; + RC_DEPTYPE *dt_np; + RC_STRINGLIST *config; + RC_STRING *s; + RC_STRING *s2; + RC_DEPTYPE *provide; + char *line; + char *depend; char *depends; char *service; char *type; - char *depend; - char **config = NULL; - int retval = true; - FILE *fp; - rc_depinfo_t *deptree = NULL; - rc_depinfo_t *depinfo; - rc_depinfo_t *di; - rc_depinfo_t *last_depinfo = NULL; - rc_deptype_t *deptype = NULL; - rc_deptype_t *dt; - rc_deptype_t *last_deptype = NULL; - char **removedp = NULL; - char *line; - size_t len; size_t i; - size_t j; size_t k; - bool already_added; - const char *sys = rc_sys (); + size_t len; + int retval = true; + const char *sys = rc_sys(); + char *nosys; /* Some init scripts need RC_LIBDIR to source stuff Ideally we should be setting our full env instead */ - if (! getenv ("RC_LIBDIR")) - setenv ("RC_LIBDIR", RC_LIBDIR, 0); + if (! getenv("RC_LIBDIR")) + setenv("RC_LIBDIR", RC_LIBDIR, 0); /* Phase 1 - source all init scripts and print dependencies */ - if (! (fp = popen (GENDEP, "r"))) - return (false); + if (! (fp = popen(GENDEP, "r"))) + return false; + + deptree = xmalloc(sizeof(*deptree)); + STAILQ_INIT(deptree); - while ((line = rc_getline (fp))) + config = rc_stringlist_new(); + + while ((line = rc_getline(fp))) { depends = line; - service = strsep (&depends, " "); + service = strsep(&depends, " "); if (! service || ! *service) goto next; - type = strsep (&depends, " "); + type = strsep(&depends, " "); - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - last_depinfo = depinfo; - if (depinfo->service && strcmp (depinfo->service, service) == 0) - break; - } - - if (! depinfo) - { - if (! last_depinfo) - deptree = depinfo = xzalloc (sizeof (*depinfo)); - else if (! last_depinfo->service) - depinfo = last_depinfo; - else - { - last_depinfo->next = xzalloc (sizeof (*last_depinfo->next)); - depinfo = last_depinfo->next; + if (! depinfo || strcmp(depinfo->service, service) != 0) { + deptype = NULL; + depinfo = get_depinfo(deptree, service); + if (! depinfo) { + depinfo = xmalloc(sizeof(*depinfo)); + STAILQ_INIT(&depinfo->depends); + depinfo->service = xstrdup(service); + STAILQ_INSERT_TAIL(deptree, depinfo, entries); } - depinfo->service = xstrdup (service); } - + /* We may not have any depends */ if (! type || ! depends) goto next; /* Get the type */ - if (strcmp (type, "config") != 0) { - last_deptype = NULL; - for (deptype = depinfo->depends; deptype; deptype = deptype->next) - { - last_deptype = deptype; - if (strcmp (deptype->type, type) == 0) - break; - } - - if (! deptype) - { - if (! last_deptype) - { - depinfo->depends = xzalloc (sizeof (*depinfo->depends)); - deptype = depinfo->depends; - } - else - { - last_deptype->next = xzalloc (sizeof (*last_deptype->next)); - deptype = last_deptype->next; - } - deptype->type = xstrdup (type); + if (strcmp(type, "config") != 0) { + if (! deptype || strcmp (deptype->type, type) != 0) + deptype = get_deptype(depinfo, type); + if (! deptype) { + deptype = xmalloc(sizeof(*deptype)); + deptype->type = xstrdup(type); + deptype->services = rc_stringlist_new(); + STAILQ_INSERT_TAIL(&depinfo->depends, deptype, entries); } } /* Now add each depend to our type. We do this individually so we handle multiple spaces gracefully */ - while ((depend = strsep (&depends, " "))) + while ((depend = strsep(&depends, " "))) { if (depend[0] == 0) continue; - if (strcmp (type, "config") == 0) { - rc_strlist_addsort (&config, depend); + if (strcmp(type, "config") == 0) { + rc_stringlist_add(config, depend); continue; } /* .sh files are not init scripts */ - len = strlen (depend); + len = strlen(depend); if (len > 2 && depend[len - 3] == '.' && depend[len - 2] == 's' && @@ -849,171 +790,114 @@ bool rc_deptree_update (void) /* Remove our dependency if instructed */ if (depend[0] == '!') { - rc_strlist_delete (&deptype->services, depend + 1); + rc_stringlist_delete(deptype->services, depend + 1); continue; } - rc_strlist_addsort (&deptype->services, depend); + rc_stringlist_add(deptype->services, depend); /* We need to allow `after *; before local;` to work. * Conversely, we need to allow 'before *; after modules' also */ /* If we're before something, remove us from the after list */ - if (strcmp (type, "ibefore") == 0) { - if ((dt = get_deptype (depinfo, "iafter"))) - rc_strlist_delete (&dt->services, depend); + if (strcmp(type, "ibefore") == 0) { + if ((dt = get_deptype(depinfo, "iafter"))) + rc_stringlist_delete(dt->services, depend); } /* If we're after something, remove us from the before list */ if (strcmp (type, "iafter") == 0 || strcmp (type, "ineed") == 0 || strcmp (type, "iuse") == 0) { - if ((dt = get_deptype (depinfo, "ibefore"))) - rc_strlist_delete (&dt->services, depend); + if ((dt = get_deptype(depinfo, "ibefore"))) + rc_stringlist_delete(dt->services, depend); } } next: - free (line); + free(line); } - pclose (fp); + pclose(fp); /* 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; - - len = strlen (sys); - nosys = xmalloc (len + 3); + len = strlen(sys); + nosys = xmalloc(len + 3); nosys[0] = 'n'; nosys[1] = 'o'; for (i = 0; i < len; i++) - nosys[i + 2] = (char) tolower ((int) sys[i]); + nosys[i + 2] = (char) tolower((int) sys[i]); nosys[i + 2] = '\0'; - last_depinfo = NULL; - depinfo = deptree; - while (depinfo) { - bool removed = false; - if ((deptype = get_deptype (depinfo, "keyword"))) { - STRLIST_FOREACH (deptype->services, service, i) - if (strcmp (service, nosys) == 0) { - if (last_depinfo) - last_depinfo->next = depinfo->next; - else - deptree = depinfo->next; - removed = true; - break; + STAILQ_FOREACH_SAFE(depinfo, deptree, entries, depinfo_np) + if ((deptype = get_deptype(depinfo, "keyword"))) + TAILQ_FOREACH(s, deptype->services, entries) + if (strcmp (s->value, nosys) == 0) { + provide = get_deptype(depinfo, "iprovide"); + STAILQ_REMOVE(deptree, depinfo, rc_depinfo, entries); + STAILQ_FOREACH(di, deptree, entries) { + STAILQ_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)) { + STAILQ_REMOVE(&di->depends, dt, rc_deptype, entries); + free(dt->type); + free(dt->services); + free(dt); + } + } + } } - } - if (removed) { - dt = get_deptype (depinfo, "iprovide"); - if (dt) - STRLIST_FOREACH (dt->services, service, i) - rc_strlist_addu (&removedp, service); - for (di = deptree; di; di = di->next) { - for (dt = di->depends; dt; dt = dt->next) - rc_strlist_delete (&dt->services, depinfo->service); - } - di = depinfo->next; - depinfo->next = NULL; - rc_deptree_free (depinfo); - depinfo = di; - } else { - last_depinfo = depinfo; - depinfo = depinfo->next; - } - } - free (nosys); } - /* Phase 3 - add our providors to the tree */ - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - if ((deptype = get_deptype (depinfo, "iprovide"))) - STRLIST_FOREACH (deptype->services, service, i) - { - for (di = deptree; di; di = di->next) - { - last_depinfo = di; - if (strcmp (di->service, service) == 0) + /* Phase 3 - add our providers to the tree */ + providers = xmalloc(sizeof(*providers)); + STAILQ_INIT(providers); + STAILQ_FOREACH(depinfo, deptree, entries) + if ((deptype = get_deptype(depinfo, "iprovide"))) + TAILQ_FOREACH(s, deptype->services, entries) { + STAILQ_FOREACH(di, providers, entries) + if (strcmp(di->service, s->value) == 0) break; - } - if (! di) - { - last_depinfo->next = xzalloc (sizeof (*last_depinfo->next)); - di = last_depinfo->next; - di->service = xstrdup (service); + if (! di) { + di = xmalloc(sizeof(*di)); + STAILQ_INIT(&di->depends); + di->service = xstrdup(s->value); + STAILQ_INSERT_TAIL(providers, di, entries); } } - } + STAILQ_CONCAT(deptree, providers); + free(providers); /* Phase 4 - backreference our depends */ - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - for (i = 0; deppairs[i].depend; i++) - { - deptype = get_deptype (depinfo, deppairs[i].depend); + STAILQ_FOREACH(depinfo, deptree, entries) + for (i = 0; deppairs[i].depend; i++) { + deptype = get_deptype(depinfo, deppairs[i].depend); if (! deptype) continue; - - STRLIST_FOREACH (deptype->services, service, j) - { - di = get_depinfo (deptree, service); - if (! di) - { + TAILQ_FOREACH(s, deptype->services, entries) { + di = get_depinfo(deptree, s->value); + if (! di) { if (strcmp (deptype->type, "ineed") == 0) - { - bool removed = false; - STRLIST_FOREACH (removedp, line, k) { - if (strcmp (line, service) == 0) { - removed = true; - break; - } - } - if (! removed) - fprintf (stderr, - "Service `%s' needs non existant service `%s'\n", - depinfo->service, service); - } + fprintf (stderr, + "Service `%s' needs non" + " existant service `%s'\n", + depinfo->service, s->value); continue; } - /* Add our deptype now */ - last_deptype = NULL; - for (dt = di->depends; dt; dt = dt->next) - { - last_deptype = dt; - if (strcmp (dt->type, deppairs[i].addto) == 0) - break; + dt = get_deptype(di, deppairs[i].addto); + if (! dt) { + dt = xmalloc(sizeof(*dt)); + dt->type = xstrdup(deppairs[i].addto); + dt->services = rc_stringlist_new(); + STAILQ_INSERT_TAIL(&di->depends, dt, entries); } - if (! dt) - { - if (! last_deptype) - { - di->depends = xzalloc (sizeof (*di->depends)); - dt = di->depends; - } - else - { - last_deptype->next = xzalloc (sizeof (*last_deptype->next)); - dt = last_deptype->next; - } - dt->type = xstrdup (deppairs[i].addto); - } - - already_added = false; - STRLIST_FOREACH (dt->services, service, k) - if (strcmp (service, depinfo->service) == 0) - { - already_added = true; - break; - } - - if (! already_added) - rc_strlist_addsort (&dt->services, depinfo->service); + rc_stringlist_add(dt->services, depinfo->service); } } - } /* Phase 5 - save to disk Now that we're purely in C, do we need to keep a shell parseable file? @@ -1021,49 +905,47 @@ next: This works and should be entirely shell parseable provided that depend names don't have any non shell variable characters in */ - if ((fp = fopen (RC_DEPTREE, "w"))) { + if ((fp = fopen (RC_DEPTREE_CACHE, "w"))) { i = 0; - for (depinfo = deptree; depinfo; depinfo = depinfo->next) - { - fprintf (fp, "depinfo_%zu_service='%s'\n", - i, depinfo->service); - for (deptype = depinfo->depends; deptype; deptype = deptype->next) - { + STAILQ_FOREACH(depinfo, deptree, entries) { + fprintf(fp, "depinfo_%zu_service='%s'\n", + i, depinfo->service); + STAILQ_FOREACH(deptype, &depinfo->depends, entries) { k = 0; - STRLIST_FOREACH (deptype->services, service, j) - { - fprintf (fp, - "depinfo_%zu_%s_%zu='%s'\n", - i, - deptype->type, - k, service); + TAILQ_FOREACH(s, deptype->services, entries) { + fprintf(fp, + "depinfo_%zu_%s_%zu='%s'\n", + i, deptype->type, k, s->value); k++; } } i++; } - fclose (fp); + fclose(fp); } else { - fprintf (stderr, "fopen `%s': %s\n", RC_DEPTREE, strerror (errno)); + fprintf(stderr, "fopen `%s': %s\n", + RC_DEPTREE_CACHE, strerror(errno)); retval = false; } /* Save our external config files to disk */ - if (config) { - if ((fp = fopen (RC_DEPCONFIG, "w"))) { - STRLIST_FOREACH (config, service, i) - fprintf (fp, "%s\n", service); - fclose (fp); + if (TAILQ_FIRST(config)) { + if ((fp = fopen(RC_DEPCONFIG, "w"))) { + TAILQ_FOREACH(s, config, entries) + fprintf (fp, "%s\n", s->value); + fclose(fp); } else { - fprintf (stderr, "fopen `%s': %s\n", RC_DEPCONFIG, strerror (errno)); + fprintf(stderr, "fopen `%s': %s\n", + RC_DEPCONFIG, strerror(errno)); retval = false; } - rc_strlist_free (config); + rc_stringlist_free (config); + } else { + unlink(RC_DEPCONFIG); } - rc_strlist_free (removedp); - rc_deptree_free (deptree); + rc_deptree_free(deptree); - return (retval); + return retval; } librc_hidden_def(rc_deptree_update) |