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 20 Aug 2026 06:24:28 -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 20 Aug 2026 06:24:28 -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,8 +667,9 @@ run_rc_command() # and return if that failed or warn # user and exit when interactive # - if [ -n "${rcvar}" ] && [ "$rc_arg" != "rcvar" ]; then - if ! checkyesno ${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 return 0 @@ -741,7 +745,7 @@ EOF # directories, and files # for _f in $required_vars; do - if ! checkyesno $_f; then + if ! checkyesno "$_f"; then warn "\$${_f} is not enabled." if [ -z "$rc_force" ]; then return 1 @@ -894,7 +898,7 @@ $command $rc_flags $command_args" rcvar) echo "# $name" if [ -n "$rcvar" ]; then - if checkyesno ${rcvar}; then + if checkyesno "${rcvar}"; then echo "${rcvar}=YES" else echo "${rcvar}=NO" @@ -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,9 +975,12 @@ 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 + # consumed by rc.subr itself, so never redirect it. + # _must_redirect=false - if _have_rc_postprocessor \ - && _has_rcorder_keyword interactive $_file + if [ "$_arg" != "skipstart" ] && _have_rc_postprocessor \ + && _has_rcorder_keyword interactive "$_file" then _must_redirect=true fi @@ -1485,4 +1500,134 @@ 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 printf YES + else + command printf 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 + if [ -d "${d}" ]; then + allf="${allf} ${d}/*" + fi + 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 printf '%s ' "${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 [ "$canskip" != YES ]; 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 (> /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 '%s\n' "${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 20 Aug 2026 06:24:28 -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 20 Aug 2026 06:24:28 -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 20 Aug 2026 06:24:28 -0000 @@ -0,0 +1,43 @@ +#!/bin/sh +# +# $NetBSD$ +# + +# KEYWORD: nostart + +$_rc_subr_loaded . /etc/rc.subr + +name=rcorder_cache +rcvar=$name +start_cmd=: +stop_cmd=: +reload_cmd=rcorder_cache_reload +restart_cmd=: +status_cmd=rcorder_cache_status +poll_cmd=: + +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 + printf '/etc/rcorder.cache is in use.\n' + else + printf '/etc/rcorder.cache will be built on next boot.\n' + fi + return 0 + else + printf '/etc/rcorder.cache is not in use.\n' + return 1 + fi +} + +load_rc_config "$name" +run_rc_command "$1" Index: distrib/sets/lists/etc/mi =================================================================== RCS file: /cvsroot/src/distrib/sets/lists/etc/mi,v retrieving revision 1.278 diff -u -p -r1.278 mi --- distrib/sets/lists/etc/mi 1 Jul 2026 03:56:27 -0000 1.278 +++ distrib/sets/lists/etc/mi 20 Aug 2026 06:24:28 -0000 @@ -296,6 +296,7 @@ ./etc/rc.d/random_seed etc-sys-rc ./etc/rc.d/rarpd etc-bootserver-rc ./etc/rc.d/rbootd etc-bootserver-rc +./etc/rc.d/rcorder_cache etc-sys-rc ./etc/rc.d/resize_root etc-sys-rc ./etc/rc.d/rndctl etc-sys-rc ./etc/rc.d/root etc-sys-rc