From 0eebf94c0d6d53d2199163a4c81232591b65da3c Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Fri, 19 Jul 2024 15:41:44 +0200 Subject: librc-depend.c: dynamically generate services for multiplexed services. when generating back references, attempt to instantiate missing services. Signed-off-by: Anna (navi) Figueiredo Gomes --- sh/gendepends.sh.in | 180 +++++++++++++++++++++++++++-------------------- src/librc/librc-depend.c | 66 +++++++++++++---- 2 files changed, 155 insertions(+), 91 deletions(-) diff --git a/sh/gendepends.sh.in b/sh/gendepends.sh.in index 8ce1c87f..85fb48c1 100644 --- a/sh/gendepends.sh.in +++ b/sh/gendepends.sh.in @@ -53,88 +53,112 @@ depend() { : } -_dirs=" - @SYSCONFDIR@/init.d - @PKG_PREFIX@/etc/init.d - @LOCAL_PREFIX@/etc/init.d -" +gendepend() { + RC_SERVICE="$1" + [ -x "$RC_SERVICE" -a -f "$RC_SERVICE" ] || continue + + # Only generate dependencies for OpenRC scripts + read one two three <"$RC_SERVICE" + case "$one" in + \#*/openrc-run) ;; + \#*/runscript) ;; + \#!) + case "$two" in + */openrc-run) ;; + */runscript) ;; + *) + continue + ;; + esac + ;; + *) + continue + ;; + esac + unset one two three + + RC_SVCNAME=${RC_SERVICE##*/}; export RC_SVCNAME + + # Compat + SVCNAME=$RC_SVCNAME; export SVCNAME + + ( + # Save stdout in fd3, then remap it to stderr + exec 3>&1 1>&2 + + _rc_c=${RC_SVCNAME%%.*} + _conf_d="${RC_SYSCONF_DIR}/conf.d" + if [ -n "$_rc_c" -a "$_rc_c" != "$RC_SVCNAME" ]; then + if [ -e "$_conf_d/$_rc_c" ]; then + . "$_conf_d/$_rc_c" + fi + fi + unset _rc_c + + if [ -e "$_conf_d/$RC_SVCNAME" ]; then + . "$_conf_d/$RC_SVCNAME" + fi + + [ -e @SYSCONFDIR@/rc.conf ] && . @SYSCONFDIR@/rc.conf + if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then + for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do + [ -e "$_f" ] && . "$_f" + done + fi + + if . "$RC_SERVICE"; then + echo "$RC_SVCNAME" >&3 + _depend + fi + ) +} -if yesno "$RC_USER_SERVICES"; then +do_all() { _dirs=" - @SYSCONFDIR@/user.d/init.d - ${XDG_CONFIG_HOME:-${HOME}/.config}/openrc/init.d + @SYSCONFDIR@/init.d + @PKG_PREFIX@/etc/init.d + @LOCAL_PREFIX@/etc/init.d " -fi -_done_dirs= -for _dir in ${_dirs} -do - [ -d "$_dir" ] || continue - - # Don't do the same dir twice - for _d in $_done_dirs; do - [ "$_d" = "$_dir" ] && continue 2 + if yesno "$RC_USER_SERVICES"; then + _dirs=" + @SYSCONFDIR@/user.d/init.d + ${XDG_CONFIG_HOME:-${HOME}/.config}/openrc/init.d + " + fi + + _done_dirs= + for _dir in ${_dirs} + do + [ -d "$_dir" ] || continue + + # Don't do the same dir twice + for _d in $_done_dirs; do + [ "$_d" = "$_dir" ] && continue 2 + done + unset _d + _done_dirs="$_done_dirs $_dir" + + cd "$_dir" + RC_SYSCONF_DIR="$_dir" + for _service in *; do + gendepend "$_dir/$_service" + done done - unset _d - _done_dirs="$_done_dirs $_dir" - - cd "$_dir" - for RC_SERVICE in *; do - [ -x "$RC_SERVICE" -a -f "$RC_SERVICE" ] || continue - - # Only generate dependencies for OpenRC scripts - read one two three <"$RC_SERVICE" - case "$one" in - \#*/openrc-run) ;; - \#*/runscript) ;; - \#!) - case "$two" in - */openrc-run) ;; - */runscript) ;; - *) - continue - ;; - esac - ;; - *) - continue - ;; - esac - unset one two three - - RC_SVCNAME=${RC_SERVICE##*/} ; export RC_SVCNAME - - # Compat - SVCNAME=$RC_SVCNAME ; export SVCNAME - - ( - # Save stdout in fd3, then remap it to stderr - exec 3>&1 1>&2 - - _rc_c=${RC_SVCNAME%%.*} - if [ -n "$_rc_c" -a "$_rc_c" != "$RC_SVCNAME" ]; then - if [ -e "$_dir/../conf.d/$_rc_c" ]; then - . "$_dir/../conf.d/$_rc_c" - fi - fi - unset _rc_c - - if [ -e "$_dir/../conf.d/$RC_SVCNAME" ]; then - . "$_dir/../conf.d/$RC_SVCNAME" - fi - - [ -e @SYSCONFDIR@/rc.conf ] && . @SYSCONFDIR@/rc.conf - if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then - for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do - [ -e "$_f" ] && . "$_f" - done - fi + unset _dirs +} - if . "$_dir/$RC_SVCNAME"; then - echo "$RC_SVCNAME" >&3 - _depend - fi - ) +do_svcs() { + for _service in $@; do + RC_SYSCONF_DIR="$(dirname $(realpath "$_service"))/.." + [ -d "${RC_SYSCONF_DIR}" ] || return 1 + cd "${RC_SYSCONF_DIR}" || return 1 + gendepend "$_service" done -done -unset _dirs +} + +if [ $# -gt 0 ]; then + do_svcs $@ +else + do_all +fi diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c index cb38f190..4f72f2df 100644 --- a/src/librc/librc-depend.c +++ b/src/librc/librc-depend.c @@ -833,7 +833,7 @@ filter_sys(RC_DEPTREE *deptree, const char *sys) } static bool -deptree_generate(RC_DEPTREE *deptree, RC_STRINGLIST **config) +deptree_generate(const char *target, RC_DEPTREE *deptree, RC_STRINGLIST **config) { FILE *fp; RC_DEPTREE *providers; @@ -854,10 +854,21 @@ deptree_generate(RC_DEPTREE *deptree, RC_STRINGLIST **config) if (uname(&uts) == 0) setenv("RC_UNAME", uts.sysname, 1); /* Phase 1 - source all init scripts and print dependencies */ - if (!(fp = popen(GENDEP, "r"))) + + if (target) { + char *cmd; + xasprintf(&cmd, GENDEP " %s", target); + fp = popen(cmd, "r"); + free(cmd); + } else { + fp = popen(GENDEP, "r"); + } + + if (!fp) return false; - *config = rc_stringlist_new(); + if (config) + *config = rc_stringlist_new(); while ((size = getline(&line, &len, fp)) != -1) { line[size - 1] = '\0'; @@ -895,7 +906,8 @@ deptree_generate(RC_DEPTREE *deptree, RC_STRINGLIST **config) continue; if (strcmp(type, "config") == 0) { - rc_stringlist_addu(*config, depend); + if (config) + rc_stringlist_addu(*config, depend); continue; } @@ -928,9 +940,9 @@ deptree_generate(RC_DEPTREE *deptree, RC_STRINGLIST **config) } /* If we're after something, remove us from the before list */ if (strcmp(type, "iafter") == 0 || - strcmp(type, "ineed") == 0 || - strcmp(type, "iwant") == 0 || - strcmp(type, "iuse") == 0) { + strcmp(type, "ineed") == 0 || + strcmp(type, "iwant") == 0 || + strcmp(type, "iuse") == 0) { if ((dt = get_deptype(depinfo, "ibefore"))) rc_stringlist_delete(dt->services, depend); } @@ -964,15 +976,42 @@ deptree_generate(RC_DEPTREE *deptree, RC_STRINGLIST **config) return true; } +static RC_DEPINFO * +make_dylink_depinfo(RC_DEPTREE *deptree, const char *service) +{ + RC_DEPINFO *di = NULL; + char *target_file = NULL; + char *base = rc_service_base(service); + if (!base) + return NULL; + target_file = rc_service_dylink(base, service); + if (!target_file) + goto out; + /* TODO: integrate configuration checking for dynamic services */ + if (!deptree_generate(target_file, deptree, NULL)) + goto out; + + di = get_depinfo(deptree, service); + +out: + free(base); + free(target_file); + return di; +} + /* 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 + and echos their dependency info to stdout and populates a depinfo object + with that data + Phase 2 filters services for system compatibility (i.e. keyword -container) Phase 3 adds any provided services to the depinfo object - Phase 4 scans that depinfo object and puts in backlinks + + Phase 4 scans that depinfo object and puts in backlinks, and dynamically + links services on the . format that are missing. 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 @@ -992,12 +1031,13 @@ rc_deptree_update(void) deptree = xmalloc(sizeof(*deptree)); TAILQ_INIT(deptree); - if (!deptree_generate(deptree, &config)) { + /* Phases 1..3 - generate intial deptree */ + if (!deptree_generate(NULL, deptree, &config)) { free(deptree); return false; } - /* Phase 4 - backreference our depends */ + /* Phase 4 - backreference our depends and dylink services */ TAILQ_FOREACH(depinfo, deptree, entries) { for (size_t i = 0; deppairs[i].depend; i++) { deptype = get_deptype(depinfo, deppairs[i].depend); @@ -1005,7 +1045,7 @@ rc_deptree_update(void) continue; TAILQ_FOREACH(s, deptype->services, entries) { di = get_depinfo(deptree, s->value); - if (!di) { + if (!di && !(di = make_dylink_depinfo(deptree, s->value))) { if (strcmp(deptype->type, "ineed") == 0) { fprintf(stderr, "Service '%s' needs non existent service '%s'\n", depinfo->service, s->value); -- cgit v1.2.3