From a3db3bac6242ff29871161620d0449125b3262aa Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Fri, 14 Dec 2007 12:24:16 +0000 Subject: Allow services to be in /usr/local/etc/init.d, but disallow them being added to the boot runlevel. --- sh/gendepends.sh | 63 ++++++++++++++++++++++++++++-------------------------- src/librc-depend.c | 2 ++ src/librc.c | 51 ++++++++++++++++++++++++++++++++++--------- src/rc-misc.h | 3 +++ src/rc-status.c | 2 +- src/rc-update.c | 37 ++++++++++++++++---------------- 6 files changed, 99 insertions(+), 59 deletions(-) diff --git a/sh/gendepends.sh b/sh/gendepends.sh index 4fb2c8ed..f6c6edb4 100755 --- a/sh/gendepends.sh +++ b/sh/gendepends.sh @@ -53,42 +53,45 @@ depend() { : } -cd /etc/init.d -for SVCNAME in *; do - [ -x "${SVCNAME}" ] || continue +for _dir in /etc/init.d /usr/local/etc/init.d; do + [ -d "${_dir}" ] || continue + cd "${_dir}" + for SVCNAME in *; do + [ -x "${SVCNAME}" ] || continue - # Only generate dependencies for runscripts - read one two < "${SVCNAME}" - [ "${one}" = "#!/sbin/runscript" ] || continue - unset one two + # Only generate dependencies for runscripts + read one two < "${SVCNAME}" + [ "${one}" = "#!/sbin/runscript" ] || continue + unset one two - SVCNAME=${SVCNAME##*/} - ( - # Save stdout in fd3, then remap it to stderr - exec 3>&1 1>&2 + SVCNAME=${SVCNAME##*/} + ( + # Save stdout in fd3, then remap it to stderr + exec 3>&1 1>&2 - rc_c=${SVCNAME%%.*} - if [ -n "${rc_c}" -a "${rc_c}" != "${SVCNAME}" ]; then - [ -e /etc/conf.d/"${rc_c}" ] && . /etc/conf.d/"${rc_c}" - fi - unset rc_c + _rc_c=${SVCNAME%%.*} + if [ -n "${_rc_c}" -a "${_rc_c}" != "${SVCNAME}" ]; then + [ -e "${_dir}/../conf.d/${_rc_c}" ] && . "${_dir}/../conf.d/${_rc_c}" + fi + unset _rc_c - [ -e /etc/conf.d/"${SVCNAME}" ] && . /etc/conf.d/"${SVCNAME}" + [ -e "${_dir}/../conf.d/${SVCNAME}" ] && . "${_dir}/../conf.d/${SVCNAME}" - if . /etc/init.d/"${SVCNAME}"; then - echo "${SVCNAME}" >&3 - depend + if . "${_dir}/${SVCNAME}"; then + echo "${SVCNAME}" >&3 + depend - # Add any user defined depends - config ${rc_config} ${RC_CONFIG} - need ${rc_need} ${RC_NEED} - use ${rc_use} ${RC_USE} - before ${rc_before} ${RC_BEFORE} - after ${rc_after} ${RC_AFTER} - provide ${rc_provide} ${RC_PROVIDE} - keywords ${rc_keywords} ${RC_KEYWORDS} - fi - ) + # Add any user defined depends + config ${rc_config} ${RC_CONFIG} + need ${rc_need} ${RC_NEED} + use ${rc_use} ${RC_USE} + before ${rc_before} ${RC_BEFORE} + after ${rc_after} ${RC_AFTER} + provide ${rc_provide} ${RC_PROVIDE} + keywords ${rc_keywords} ${RC_KEYWORDS} + fi + ) + done done # vim: set ts=4 : diff --git a/src/librc-depend.c b/src/librc-depend.c index ee6c79b7..e870c73c 100644 --- a/src/librc-depend.c +++ b/src/librc-depend.c @@ -673,6 +673,8 @@ bool rc_deptree_update_needed (void) /* Quick test to see if anything we use has changed */ if (! is_newer_than (RC_DEPTREE, RC_INITDIR) || ! is_newer_than (RC_DEPTREE, RC_CONFDIR) || + ! is_newer_than (RC_DEPTREE, RC_INITDIR_LOCAL) || + ! is_newer_than (RC_DEPTREE, RC_CONFDIR_LOCAL) || ! is_newer_than (RC_DEPTREE, "/etc/rc.conf")) return (true); diff --git a/src/librc.c b/src/librc.c index e429318b..61f91525 100644 --- a/src/librc.c +++ b/src/librc.c @@ -71,6 +71,7 @@ static char **ls_dir (const char *dir, int options) DIR *dp; struct dirent *d; char **list = NULL; + struct stat buf; if ((dp = opendir (dir)) == NULL) return (NULL); @@ -79,11 +80,14 @@ static char **ls_dir (const char *dir, int options) if (d->d_name[0] != '.') { if (options & LS_INITD) { int l = strlen (d->d_name); - char *init = rc_strcatpaths (RC_INITDIR, d->d_name, - (char *) NULL); - bool ok = exists (init); - free (init); - if (! ok) + + /* Check that our file really exists. + * This is important as a service maybe in a runlevel, but + * could also have been removed. */ + char *file = rc_strcatpaths (dir, d->d_name, NULL); + int ok = stat (file, &buf); + free (file); + if (ok != 0) continue; /* .sh files are not init scripts */ @@ -93,8 +97,6 @@ static char **ls_dir (const char *dir, int options) continue; } if (options & LS_DIR) { - struct stat buf; - if (stat (d->d_name, &buf) == 0 && ! S_ISDIR (buf.st_mode)) continue; } @@ -258,8 +260,15 @@ char *rc_service_resolve (const char *service) if (r > 0) return (xstrdup (buffer)); } - snprintf (buffer, sizeof (buffer), RC_INITDIR "/%s", service); + + /* So we don't exist in /etc/init.d - check /usr/local/etc/init.d */ + if (stat (buffer, &buf) != 0) { + snprintf (buffer, sizeof (buffer), RC_INITDIR_LOCAL "/%s", service); + if (stat (buffer, &buf) != 0) + return (NULL); + } + return (xstrdup (buffer)); } librc_hidden_def(rc_service_resolve) @@ -717,8 +726,16 @@ char **rc_services_in_runlevel (const char *runlevel) char *dir; char **list = NULL; - if (! runlevel) - return (ls_dir (RC_INITDIR, LS_INITD)); + if (! runlevel) { + int i; + char **local = ls_dir (RC_INITDIR_LOCAL, LS_INITD); + + list = ls_dir (RC_INITDIR, LS_INITD); + STRLIST_FOREACH (local, dir, i) + rc_strlist_addsortu (&list, dir); + rc_strlist_free (local); + return (list); + } /* These special levels never contain any services */ if (strcmp (runlevel, RC_LEVEL_SYSINIT) == 0 || @@ -785,6 +802,20 @@ bool rc_service_add (const char *runlevel, const char *service) } init = rc_service_resolve (service); + + /* We need to ensure that only things in /etc/init.d are added + * to the boot runlevel */ + if (strcmp (runlevel, RC_LEVEL_BOOT) == 0) { + char *tmp = xstrdup (init); + retval = (strcmp (dirname (tmp), RC_INITDIR) == 0); + free (tmp); + if (! retval) { + free (init); + errno = EPERM; + return (false); + } + } + svc = xstrdup (service); file = rc_strcatpaths (RC_RUNLEVELDIR, runlevel, basename (svc), (char *) NULL); diff --git a/src/rc-misc.h b/src/rc-misc.h index bb3b33dc..985726d3 100644 --- a/src/rc-misc.h +++ b/src/rc-misc.h @@ -51,6 +51,9 @@ #define RC_INITDIR "/etc/init.d" #define RC_CONFDIR "/etc/conf.d" +#define RC_INITDIR_LOCAL "/usr/local/etc/init.d" +#define RC_CONFDIR_LOCAL "/usr/local/etc/conf.d" + #define RC_KSOFTLEVEL RC_SVCDIR "/ksoftlevel" #define RC_STARTING RC_SVCDIR "/rc.starting" #define RC_STOPPING RC_SVCDIR "/rc.stopping" diff --git a/src/rc-status.c b/src/rc-status.c index dc515af7..535f438a 100644 --- a/src/rc-status.c +++ b/src/rc-status.c @@ -170,7 +170,7 @@ int rc_status (int argc, char **argv) /* Output the services in the order in which they would start */ if (geteuid () == 0) - deptree = _rc_deptree_load (); + deptree = _rc_deptree_load (NULL); else deptree = rc_deptree_load (); diff --git a/src/rc-update.c b/src/rc-update.c index ddec0066..d5f2ba92 100644 --- a/src/rc-update.c +++ b/src/rc-update.c @@ -60,8 +60,6 @@ static ssize_t add (const char *runlevel, const char *service) if (! rc_service_exists (service)) eerror ("%s: service `%s' does not exist", applet, service); - else if (! rc_runlevel_exists (runlevel)) - eerror ("%s: runlevel `%s' does not exist", applet, runlevel); else if (rc_service_in_runlevel (service, runlevel)) { ewarn ("%s: %s already installed in runlevel `%s'; skipping", applet, service, runlevel); @@ -80,19 +78,18 @@ static ssize_t delete (const char *runlevel, const char *service) { ssize_t retval = -1; - if (rc_service_in_runlevel (service, runlevel)) { - if (rc_service_delete (runlevel, service)) { - einfo ("%s removed from runlevel %s", service, runlevel); - retval = 1; - } else - eerror ("%s: failed to remove service `%s' from runlevel `%s': %s", - applet, service, runlevel, strerror (errno)); - } else if (! rc_service_exists (service)) - eerror ("%s: service `%s' does not exist", applet, service); - else if (! rc_runlevel_exists (runlevel)) - eerror ("%s: runlevel `%s' does not exist", applet, runlevel); - else - retval = 0; + errno = 0; + if (rc_service_delete (runlevel, service)) { + einfo ("%s removed from runlevel %s", service, runlevel); + return 1; + } + + if (errno == ENOENT) + eerror ("%s: service `%s' is not in the runlevel `%s'", + applet, service, runlevel); + else + eerror ("%s: failed to remove service `%s' from runlevel `%s': %s", + applet, service, runlevel, strerror (errno)); return (retval); } @@ -238,11 +235,10 @@ int rc_update (int argc, char **argv) } else { if (! service) eerror ("%s: no service specified", applet); - else if (! rc_service_exists (service)) - eerror ("%s: service `%s' does not exist", applet, service); else { ssize_t num_updated = 0; ssize_t (*actfunc)(const char *, const char *); + size_t ret; if (action & DOADD) { actfunc = add; @@ -259,7 +255,12 @@ int rc_update (int argc, char **argv) eerrorx ("%s: no runlevels found", applet); STRLIST_FOREACH (runlevels, runlevel, i) { - ssize_t ret = actfunc (runlevel, service); + if (! rc_runlevel_exists (runlevel)) { + eerror ("%s: runlevel `%s' does not exist", applet, runlevel); + continue; + } + + ret = actfunc (runlevel, service); if (ret < 0) retval = EXIT_FAILURE; num_updated += ret; -- cgit v1.2.3