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 19 Aug 2026 15:34:33 -0000 @@ -140,20 +140,28 @@ 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. + # + 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 @@ -162,10 +170,14 @@ rc_real_work() # for _rc_elem in $files; do print_rc_metadata "cmd-name:$_rc_elem" - run_rc_script $_rc_elem start + run_rc_script "$_rc_elem" start 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 19 Aug 2026 15:34:33 -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,9 @@ wait_for_pids() # # rcvar Display what rc.conf variable is used (if any). # +# skipstart Prints YES iff the script uses an rcvar and it +# evaluates to NO. +# # Variables available to methods, and after run_rc_command() has # completed: # @@ -617,7 +620,7 @@ run_rc_command() ;; esac - _keywords="start stop restart rcvar" + _keywords="start stop restart rcvar skipstart" if [ -n "$extra_commands" ]; then _keywords="${_keywords} ${extra_commands}" fi @@ -664,7 +667,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" != "skipstart" ]; then if ! checkyesno ${rcvar}; then # check whether interactive or not if [ -n "$_run_rc_script" ]; then @@ -902,6 +906,14 @@ $command $rc_flags $command_args" fi ;; + skipstart) + if [ -n "$rcvar" ] && ! checkyesno ${rcvar}; then + command echo YES + else + command echo NO + fi + ;; + *) rc_usage "$_keywords" ;; @@ -963,8 +975,11 @@ run_rc_script() rcvar required_dirs required_files required_vars eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd + # "skipstart" is not an interactive directive; the output is + # the output is consumed by rc.subr itself, so never redirect + # it. _must_redirect=false - if _have_rc_postprocessor \ + if [ "$_arg" != "skipstart" ] && _have_rc_postprocessor \ && _has_rcorder_keyword interactive $_file then _must_redirect=true @@ -1485,4 +1500,132 @@ 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 + command echo YES + else + command 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 d + local f + local allf + + if _rc_order_use_cache && [ -f /etc/rcorder.cache ]; then + # Listed here in order of most-likely-to-change. + allf="/etc/rc.conf /etc/rc.conf.d /etc/rc.conf.d/"* + for d in ${rc_directories:-/etc/rc.d}; do + allf="$allf ${d}/"* + done + allf="$allf /etc/defaults/rc.conf" + + 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 + local canskip + + print_rc_metadata "cmd-name:rcorder" + allf=$(for d in ${rc_directories:-/etc/rc.d}; do + test -d "$d" && command 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 + + # N.B. we only consider the script skip-able if it affirmatively + # answers "YES" on stdout to the skipstart directive. + # + printf "Updating /etc/rcorder.cache..." + _rc_ordered_script_list="" + for f in ${orderedf}; do + twiddle + canskip=$(run_rc_script "$f" skipstart) 2>/dev/null + if [ x"$canskip" != xYES ]; then + _rc_ordered_script_list="$_rc_ordered_script_list $f" + fi + done + printf "done.\n" +} + +# +# 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 (command printf "" > /etc/rcorder.cache.tmp) 2>/dev/null; then + printf "Saving updated /etc/rcorder.cache.\n" + for f in $_rc_ordered_script_list; do + command printf "${f}\n" >> /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 19 Aug 2026 15:34:33 -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 only the rc.d scripts that do useful work across reboots, +# reducing subsequent boot times. +# +rcorder_cache=NO + # If this is set to NO, shutdown(8) will not run /etc/rc.shutdown. # do_rcshutdown=YES Index: etc/rc.d/Makefile =================================================================== RCS file: /cvsroot/src/etc/rc.d/Makefile,v retrieving revision 1.119 diff -u -p -r1.119 Makefile --- etc/rc.d/Makefile 29 Dec 2024 09:47:49 -0000 1.119 +++ etc/rc.d/Makefile 19 Aug 2026 15:34:33 -0000 @@ -35,8 +35,8 @@ CONFIGFILES=\ perusertmp pf pf_boot pflogd powerd ppp pwcheck \ quota \ racoon rpcbind raidframe raidframeparity random_seed rarpd \ - rbootd resize_root rndctl root route6d routed rtadvd \ - rtclocaltime rwho \ + rbootd rcorder_cache resize_root rndctl root route6d routed \ + rtadvd rtclocaltime rwho \ savecore screenblank securelevel smtoff sshd \ staticroute swap1 swap2 sysctl sysdb syslogd \ timed tpctl ttys \ 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 19 Aug 2026 15:34:33 -0000 @@ -0,0 +1,43 @@ +#!/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" + +extra_commands="reload status" + +rcorder_cache_reload() +{ + _rc_order_build_list + _rc_order_save_cache +} + +rcorder_cache_status() +{ + if checkyesno ${rcvar}; then + if [ -f /etc/rcorder.cache ]; then + echo "/etc/rcorder.cache is in use." + else + echo "/etc/rcorder.cache will be built on next boot." + fi + return 0 + else + echo "/etc/rcorder.cache is not in use." + return 1 + fi +} + +load_rc_config $name +run_rc_command "$1"