rc.d scripts can be missed if they aren't ordered with respect to the early-late divider

Ryan Stone rysto32 at gmail.com
Fri Apr 29 15:57:54 UTC 2011


The only day I ran into an issue where certain rc.d scripts were being
skipped during boot.  I investigated it and the problem was that when
rc went to execute the early rc.d scripts, rcorder placed the missed
scripts after the early-late divider.  However when rcorder was run
the second time the missed scripts were placed before the early-late
divider.  Because of this, rc skipped over those scripts incorrectly.

Ultimately, the problem is that we don't have a total ordering over
the rc.d scripts.  This means that the sequence produced by rcorder
isn't guaranteed to be consistent.  In particular, if an rc.d script
is not ordered with respect to the early-late divider rcorder is free
to place it either before or after the divider.  If you're unlucky,
rcorder may reorder a script on the second invocation.

Below I have a patch that fixes the issue for me.  Rather than making
the incorrect assumption that the second rcorder invocation will
create a sequence that is consistent with the first invocation, and
skipping all scripts that the second invocation orders before the
early-late divider, I instead have rc track with rc.d scripts have
already run, and when running the late rc.d scripts rc skips all
scripts that have yet to run.

There's one caveat to this patch.  It assumes that you don't have two
different scripts in /etc/rc.d named foo and foo.sh (or foo.bar, for
that matter).  I can't figure out a way to resolve this with the
limited facilities available to rc before the early scripts have been
run, but maybe somebody else has an idea?

--- rc  (revision 221208)
+++ rc  (working copy)
@@ -86,6 +86,9 @@

 for _rc_elem in ${files}; do
        run_rc_script ${_rc_elem} ${_boot}
+       _rc_basename=${_rc_elem##*/}
+       eval _${_rc_basename%%.*}_has_run=1
+       unset _rc_basename

        case "$_rc_elem" in
        */${early_late_divider})        break ;;
@@ -103,13 +106,16 @@
 esac

 files=`rcorder ${skip} /etc/rc.d/* ${local_rc} 2>/dev/null`
-_skip_early=1
 for _rc_elem in ${files}; do
-       case "$_skip_early" in
-       1)      case "$_rc_elem" in
-               */${early_late_divider})        _skip_early=0 ;;
-               esac
-               continue
+       case "$_rc_elem" in
+       /etc/rc.d/*)
+               _rc_basename=${_rc_elem##*/}
+               eval _has_run=\$_${_rc_basename%%.*}_has_run
+               if [ -n "$_has_run" ]; then
+                       unset _has_run _rc_basename
+                       continue
+               fi
+               unset _has_run _rc_basename
                ;;
        esac


More information about the freebsd-rc mailing list