Index: etc/rc =================================================================== RCS file: /cvsroot/src/etc/rc,v retrieving revision 1.175 diff -u -p -r1.175 rc --- etc/rc 8 Sep 2020 16:10:53 -0000 1.175 +++ etc/rc 17 Aug 2026 20:16:25 -0000 @@ -140,20 +140,35 @@ rc_real_work() ) & # - # Get a list of all rc.d scripts, and use rcorder to choose - # what order to execute them. + # Get a list of all rc.d scripts and the order in which to + # execute them. We first use rcorder to select the overall + # total order, and then filter out the scripts that will not + # do any work using the "doeswork" directive. If the script + # does no work, it is elided from the list. This pared down + # list is then cached so subsequent boots can perform fewer + # checks, this improving boot time. The cache is invalidated + # implicitly if any of the $rc_directories or if /etc/rc.conf + # is newer than /etc/rcorder.cache. + # + if ! _rc_order_cache_is_valid; then + _rc_update_rcorder_cache=YES + _rc_order_build_list + else + _rc_update_rcorder_cache=NO + fi + + # + # $_rc_ordered_script_list now contains the rc.d scripts + # to process. + # + files="$_rc_ordered_script_list" + # # For testing, allow RC_FILES_OVERRIDE from the environment to # override this. # - print_rc_metadata "cmd-name:rcorder" - scripts=$(for rcd in ${rc_directories:-/etc/rc.d}; do - test -d ${rcd} && echo ${rcd}/*; - done) - files=$(rcorder -s nostart ${rc_rcorder_flags} ${scripts}) - print_rc_metadata "cmd-status:rcorder:$?" - if [ -n "${RC_FILES_OVERRIDE}" ]; then + _rc_update_rcorder_cache=NO files="${RC_FILES_OVERRIDE}" fi @@ -166,6 +181,10 @@ rc_real_work() print_rc_metadata "cmd-status:$_rc_elem:$?" done + if [ $_rc_update_rcorder_cache = YES ]; then + _rc_order_save_cache + fi + print_rc_metadata "end:$(date)" exit 0 ) Index: etc/rc.subr =================================================================== RCS file: /cvsroot/src/etc/rc.subr,v retrieving revision 1.111 diff -u -p -r1.111 rc.subr --- etc/rc.subr 22 May 2022 11:27:33 -0000 1.111 +++ etc/rc.subr 17 Aug 2026 20:16:25 -0000 @@ -1,6 +1,6 @@ # $NetBSD: rc.subr,v 1.111 2022/05/22 11:27:33 andvar Exp $ # -# Copyright (c) 1997-2011 The NetBSD Foundation, Inc. +# Copyright (c) 1997-2011, 2026 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation @@ -567,6 +567,11 @@ wait_for_pids() # # rcvar Display what rc.conf variable is used (if any). # +# doeswork Returns 0 if the script does work that's needed +# for boot, non-zero otherwise. Scripts are considered +# to do work if either their rcvar is set to YES or +# if they do not have a defined rcvar. +# # Variables available to methods, and after run_rc_command() has # completed: # @@ -617,7 +622,7 @@ run_rc_command() ;; esac - _keywords="start stop restart rcvar" + _keywords="start stop restart rcvar doeswork" if [ -n "$extra_commands" ]; then _keywords="${_keywords} ${extra_commands}" fi @@ -664,7 +669,8 @@ run_rc_command() # and return if that failed or warn # user and exit when interactive # - if [ -n "${rcvar}" ] && [ "$rc_arg" != "rcvar" ]; then + if [ -n "${rcvar}" ] && [ "$rc_arg" != "rcvar" ] && \ + [ "$rc_arg" != "doeswork" ]; then if ! checkyesno ${rcvar}; then # check whether interactive or not if [ -n "$_run_rc_script" ]; then @@ -902,6 +908,18 @@ $command $rc_flags $command_args" fi ;; + doeswork) + if [ -n "$rcvar" ]; then + if checkyesno ${rcvar}; then + return 0 + else + return 1 + fi + else + return 0 + fi + ;; + *) rc_usage "$_keywords" ;; @@ -1485,4 +1503,123 @@ kat() { done } +# +# Check to see if we should use the rcorder.cache. We cache the +# result in the global var _rc_order_cache_setting to avoid repeated +# sub-shells and I/O. Returns 0 if the cache should be used, non- +# zero otherwise. +# +_rc_order_use_cache() +{ + if [ -z "$_rc_order_cache_setting" ]; then + _rc_order_cache_setting=$(load_rc_config rcorder_cache; + if checkyesno rcorder_cache; then + echo YES + else + echo NO + fi) + fi + + if [ $_rc_order_cache_setting = YES ]; then + return 0 + fi + return 1 +} + +# +# Check to see if the rcorder.cache is valid. Returns 0 (success) +# if so, non-zero otherwise. The global var $_rc_ordered_script_list +# is populated with the cache's contents when the cache is valid. +# +_rc_order_cache_is_valid() +{ + local f + local allf + + # Listed here in order of most-likely-to-change. + allf="/etc/rc.conf /etc/rc.conf.d /etc/rc.conf.d/*" + allf="$allf ${rc_directories:-/etc/rc.d} /etc/defaults/rc.conf" + + if [ -f /etc/rcorder.cache ] && _rc_order_use_cache; then + for f in ${allf}; do + if [ $f -nt /etc/rcorder.cache ]; then + return 1 + fi + done + allf=$(cat /etc/rcorder.cache) + + # Verify there is at least one valid file in the + # cache. + for f in ${allf}; do + if [ -f $f ]; then + _rc_ordered_script_list="$allf" + return 0 + fi + done + fi + return 1 +} + +# +# Build the ordered script list. If we're going to rebuild the cache, +# then prints status information on the console. Sets the global var +# $_rc_ordered_script_list to the updated ordered list. +# +_rc_order_build_list() +{ + local d + local f + local allf + local orderedf + + print_rc_metadata "cmd-name:rcorder" + allf=$(for d in ${rc_directories:-/etc/rc.d}; do + test -d $d && echo ${d}/*; + done) + orderedf=$(rcorder -s nostart ${rc_rcorder_flags} ${allf}) + print_rc_metadata "cmd-status:rcorder:$?" + + if ! _rc_order_use_cache; then + _rc_ordered_script_list="$orderedf" + return + fi + + echo -n "Updating /etc/rcorder.cache..." + _rc_ordered_script_list="" + for f in ${orderedf}; do + twiddle + if run_rc_script $f doeswork; then + _rc_ordered_script_list="$_rc_ordered_script_list $f" + fi + done + echo "done." +} + +# +# Save the rcorder.cache, in the global var $_rc_ordered_script_list, +# to /etc/rcorder.cache. +# +_rc_order_save_cache() +{ + local f + + if ! _rc_order_use_cache; then + return + fi + + # + # Attempt to create an empty temporary /etc/rcorder.cache + # file, suppressing all error messages, and check for success. + # If not successful, we probably have a read-only root file + # system and thus should not proceed. + # + if (echo -n "" > /etc/rcorder.cache.tmp) 2>/dev/null; then + echo "Saving updated /etc/rcorder.cache." + for f in $_rc_ordered_script_list; do + echo "$f" >> /etc/rcorder.cache.tmp + done + mv /etc/rcorder.cache.tmp /etc/rcorder.cache + fi +} + _rc_subr_loaded=: Index: etc/defaults/rc.conf =================================================================== RCS file: /cvsroot/src/etc/defaults/rc.conf,v retrieving revision 1.169 diff -u -p -r1.169 rc.conf --- etc/defaults/rc.conf 16 Aug 2026 09:25:55 -0000 1.169 +++ etc/defaults/rc.conf 17 Aug 2026 20:16:25 -0000 @@ -45,6 +45,11 @@ rc_rcorder_flags="" # These directories must be part of the root file system. rc_directories=/etc/rc.d +# Cache the list of rc.d scripts that do useful work across reboots, +# reducing subsequent boot times. +# +rcorder_cache=YES + # If this is set to NO, shutdown(8) will not run /etc/rc.shutdown. # do_rcshutdown=YES Index: etc/rc.d/rcorder_cache =================================================================== RCS file: etc/rc.d/rcorder_cache diff -N etc/rc.d/rcorder_cache --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ etc/rc.d/rcorder_cache 17 Aug 2026 20:16:25 -0000 @@ -0,0 +1,40 @@ +#!/bin/sh +# +# $NetBSD$ +# + +# KEYWORD: nostart + +$_rc_subr_loaded . /etc/rc.subr + +name="rcorder_cache" +rcvar=$name +start_cmd="true" +stop_cmd="true" +reload_cmd="rcorder_cache_reload" +restart_cmd="true" +status_cmd="rcorder_cache_status" +poll_cmd="true" +doeswork_cmd="false" + +extra_commands="reload status" + +rcorder_cache_reload() +{ + _rc_order_build_list + _rc_order_save_cache +} + +rcorder_cache_status() +{ + if [ -f /etc/rcorder.cache ] && checkyesno ${rcvar}; then + echo "/etc/rcorder.cache is in use." + return 0 + else + echo "/etc/rcorder.cache is not in use." + return 1 + fi +} + +load_rc_config $name +run_rc_command "$1"