diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5 index 23a65935c95a..53c69f0f673c 100644 --- a/stand/defaults/loader.conf.5 +++ b/stand/defaults/loader.conf.5 @@ -1,456 +1,459 @@ .\" Copyright (c) 1999 Daniel C. Sobral .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .Dd July 31, 2021 .Dt LOADER.CONF 5 .Os .Sh NAME .Nm loader.conf .Nd "system bootstrap configuration information" .Sh DESCRIPTION The file .Nm contains descriptive information on bootstrapping the system. Through it you can specify the kernel to be booted, parameters to be passed to it, and additional modules to be loaded; and generally set all variables described in .Xr loader 8 . .Sh SYNTAX Though .Nm Ns 's format was defined explicitly to resemble .Xr rc.conf 5 , and can be sourced by .Xr sh 1 , some settings are treated in a special fashion. Also, the behavior of some settings is defined by the setting's suffix; the prefix identifies which module the setting controls. .Pp The general parsing rules are: .Bl -bullet .It Spaces and empty lines are ignored. .It A # sign will mark the remainder of the line as a comment. .It Only one setting can be present on each line. .El .Pp All settings have the following format: .Pp .Dl variable="value" .Pp Unless it belongs to one of the classes of settings that receive special treatment, a setting will set the value of a .Xr loader 8 environment variable. The settings that receive special treatment are listed below. Settings beginning with .Qq * below define the modules to be loaded and may have any prefix; the prefix identifies a module. All such settings sharing a common prefix refer to the same module. .Bl -tag -width Ar .It Ar autoboot_delay Delay in seconds before automatically booting. A user with console access will be able to interrupt the .Ic autoboot process and escape into the interactive mode by pressing a key on the console during this delay. .Pp If set to .Dq Li NO , no .Ic autoboot is automatically attempted after processing .Pa /boot/loader.rc , though explicit .Ic autoboot Ns 's are processed normally, using a 10 second delay. .Pp If set to .Dq Li 0 , no delay is inserted, but any keys pressed while the kernel and modules are loaded will enter interactive mode. .Pp If set to .Dq Li -1 , no delay will be inserted and .Nm starts interactive mode only if .Ic autoboot has failed. In combination with the .Va beastie_disable option, this option prevents users with console access from being able to interrupt the .Ic autoboot process and escape to the loader prompt. To use the .Va autoboot_delay option in this manner, .Va beastie_disable must be set to .Dq Li YES . .It Ar exec Immediately executes a .Xr loader 8 command. This type of setting cannot be processed by programs other than .Xr loader 8 , so its use should be avoided. Multiple instances of it will be processed independently. .It Ar loader_conf_dirs Space separated list of directories to process for configuration files. The lua-based loader will process files with a .Dq .conf suffix that are placed in these directories. .It Ar loader_conf_files Defines additional configuration files to be processed right after the present file. .Ar loader_conf_files should be treated as write-only. One cannot depend on any value remaining in the loader environment or carried over into the kernel environment. .It Ar kernel Name of the kernel to be loaded. If no kernel name is set, no additional modules will be loaded. The name must be a subdirectory of .Pa /boot that contains a kernel. .It Ar kernel_options Flags to be passed to the kernel. .It Ar vfs.root.mountfrom Specify the root partition to mount. For example: .Pp .Dl vfs.root.mountfrom="ufs:/dev/da0s1a" .Pp .Xr loader 8 automatically calculates the value of this tunable from .Pa /etc/fstab from the partition the kernel was loaded from. The calculated value might be calculated incorrectly when .Pa /etc/fstab is not available during .Xr loader 8 startup (as during diskless booting from NFS), or if a different device is desired by the user. The preferred value can be set in .Pa /loader.conf . .Pp The value can also be overridden from the .Xr loader 8 command line. This is useful for system recovery when .Pa /etc/fstab is damaged, lost, or read from the wrong partition. .It Ar password Protect boot menu with a password without interrupting .Ic autoboot process. The password should be in clear text format. If a password is set, boot menu will not appear until any key is pressed during countdown period specified by .Va autoboot_delay variable or .Ic autoboot process fails. In both cases user should provide specified password to be able to access boot menu. .It Ar bootlock_password Provides a password to be required by check-password before execution is allowed to continue. The password should be in clear text format. If a password is set, the user must provide specified password to boot. .It Ar verbose_loading If set to .Dq YES , module names will be displayed as they are loaded. .It Ar module_blacklist Blacklist of modules. Modules specified in the blacklist may not be loaded automatically with a .Ar *_load directive, but they may be loaded directly at the .Xr loader 8 prompt. Blacklisted modules may still be loaded indirectly as dependencies of other modules. .It Ar *_load If set to .Dq YES , that module will be loaded. If no name is defined (see below), the module's name is taken to be the same as the prefix. .It Ar *_name Defines the name of the module. .It Ar *_type Defines the module's type. If none is given, it defaults to a kld module. .It Ar *_flags Flags and parameters to be passed to the module. .It Ar *_before Commands to be executed before the module is loaded. Use of this setting should be avoided. .It Ar *_after Commands to be executed after the module is loaded. Use of this setting should be avoided. .It Ar *_error Commands to be executed if the loading of a module fails. Except for the special value .Dq abort , which aborts the bootstrap process, use of this setting should be avoided. .El .Pp .Em WARNING : developers should never use these suffixes for any kernel environment variables (tunables) or conflicts will result. .Sh DEFAULT SETTINGS Most of .Nm Ns 's default settings can be ignored. The few of them which are important or useful are: .Bl -tag -width bootfile -offset indent .It Va bitmap_load .Pq Dq NO If set to .Dq YES , a bitmap will be loaded to be displayed on screen while booting. .It Va bitmap_name .Pq Dq Pa /boot/splash.bmp Name of the bitmap to be loaded. Any other name can be used. .It Va comconsole_speed .Dq ( 9600 or the value of the .Va BOOT_COMCONSOLE_SPEED variable when .Xr loader 8 was compiled). Sets the speed of the serial console. If the previous boot loader stage specified that a serial console is in use then the default speed is determined from the current serial port speed setting. .It Va console .Pq Dq vidconsole .Dq comconsole selects serial console, .Dq vidconsole selects the video console, .Dq efi selects the EFI console, .Dq nullconsole selects a mute console (useful for systems with neither a video console nor a serial port), and .Dq spinconsole selects the video console which prevents any input and hides all output replacing it with .Dq spinning character (useful for embedded products and such). .It Va screen.font Set font size for framebuffer mode. Default font size is selected based on screen resolution, to achieve terminal dimensions 80x24. .It Va screen.textmode Value .Dq 0 will trigger BIOS loader to switch to use VESA BIOS Extension (VBE) frame buffer mode for console. The same effect can be achieved by setting .Va vbe_max_resolution . .Pp Value .Dq 1 will force BIOS loader to use VGA text mode. .Pp If .Va vbe_max_resolution is not set, the loader will try to set screen resolution based on EDID information. If EDID is not available, the default resolution is 800x600 (if available). .It Va screen.height .It Va screen.width .It Va screen.depth .Va screen.height , .Va screen.width , .Va screen.depth are set by loader when loader is using framebuffer mode to draw the screen. .It Va efi_max_resolution .It Va vbe_max_resolution Specify the maximum desired resolution for the EFI or VBE framebuffer console. The following values are accepted: .Bl -column "WidthxHeight" .It Sy Value Ta Sy Resolution .It 480p Ta 640x480 .It 720p Ta 1280x720 .It 1080p Ta 1920x1080 .It 2160p Ta 3840x2160 .It 4k Ta 3840x2160 .It 5k Ta 5120x2880 .It Va Width Ns x Ns Va Height Ta Va Width Ns x Ns Va Height .El .It Va kernel .Pq Dq kernel .It Va kernels .Pq Dq kernel kernel.old Space or comma separated list of kernels to present in the boot menu. .It Va loader_conf_files .Pq Dq Pa /boot/loader.conf /boot/loader.conf.local .It Va loader_conf_dirs .Pq Dq Pa /boot/loader.conf.d .It Va splash_bmp_load .Pq Dq NO If set to .Dq YES , will load the splash screen module, making it possible to display a bmp image on the screen while booting. .It Va splash_pcx_load .Pq Dq NO If set to .Dq YES , will load the splash screen module, making it possible to display a pcx image on the screen while booting. .It Va vesa_load .Pq Dq NO If set to .Dq YES , the vesa module will be loaded, enabling bitmaps above VGA resolution to be displayed. .It Va beastie_disable If set to .Dq YES , the beastie boot menu will be skipped. .It Va loader_logo Pq Dq Li orbbw Selects a desired logo in the beastie boot menu. Possible values are: .Dq Li orbbw , .Dq Li orb , .Dq Li fbsdbw , .Dq Li beastiebw , .Dq Li beastie , and .Dq Li none . .It Va loader_color If set to .Dq NO , the beastie boot menu will be displayed without ANSI coloring. .It Va entropy_cache_load .Pq Dq YES If set to .Dq NO , the very early boot-time entropy file will not be loaded. See the entropy entries in .Xr rc.conf 5 . .It Va entropy_cache_name .Pq Dq /boot/entropy The name of the very early boot-time entropy cache file. .It Va cpu_microcode_load .Pq Dq NO If set to .Dq YES , the microcode update file specified by .Va cpu_microcode_name will be loaded and applied very early during boot. This provides functionality similar to .Xr cpucontrol 8 but ensures that CPU features enabled by microcode updates can be used by the kernel. The update will be re-applied automatically when resuming from an ACPI sleep state. If the update file contains updates for multiple processor models, the kernel will search for and extract a matching update. Currently this setting is supported only on Intel .Dv i386 and .Dv amd64 processors. It has no effect on other processor types. .It Va cpu_microcode_name A path to a microcode update file. .El .Sh OTHER SETTINGS Other settings that may be used in .Nm that have no default value: .Bl -tag -width bootfile -offset indent .It Va fdt_overlays Specifies a comma-delimited list of FDT overlays to apply. .Pa /boot/dtb/overlays is created by default for overlays to be placed in. .It Va kernels_autodetect If set to .Dq YES , attempt to auto-detect kernels installed in .Pa /boot . This is an option specific to the Lua-based loader. It is not available in the default Forth-based loader. .El .Sh FILES .Bl -tag -width /boot/defaults/loader.conf -compact .It Pa /boot/defaults/loader.conf default settings \(em do not change this file. .It Pa /boot/loader.conf user defined settings. +.It Pa /boot/loader.conf.lua +user defined settings written in lua. .It Pa /boot/loader.conf.local machine-specific settings for sites with a common loader.conf. .El .Sh SEE ALSO +.Xr loader.conf.lua 5 , .Xr rc.conf 5 , .Xr boot 8 , .Xr cpucontrol 8 , .Xr loader 8 , .Xr loader.4th 8 .Sh HISTORY The file .Nm first appeared in .Fx 3.2 . .Sh AUTHORS This manual page was written by .An Daniel C. Sobral Aq dcs@FreeBSD.org . .Sh BUGS The .Xr loader 8 stops reading .Nm when it encounters a syntax error, so any options which are vital for booting a particular system (i.e., .Dq Va hw.ata.ata_dma Ns "=0" ) should precede any experimental additions to .Nm . diff --git a/stand/lua/Makefile b/stand/lua/Makefile index fe6fd6f63c8e..bc7c294dfda0 100644 --- a/stand/lua/Makefile +++ b/stand/lua/Makefile @@ -1,32 +1,33 @@ # $FreeBSD$ .include -MAN= cli.lua.8 \ +MAN= loader.conf.lua.5 \ + cli.lua.8 \ color.lua.8 \ config.lua.8 \ core.lua.8 \ drawer.lua.8 \ hook.lua.8 \ menu.lua.8 \ password.lua.8 \ screen.lua.8 FILESDIR= ${LUAPATH} FILES= cli.lua \ color.lua \ config.lua \ core.lua \ drawer.lua \ hook.lua \ loader.lua \ gfx-beastie.lua \ gfx-beastiebw.lua \ gfx-fbsdbw.lua \ gfx-orb.lua \ gfx-orbbw.lua \ menu.lua \ password.lua \ screen.lua .include diff --git a/stand/lua/config.lua b/stand/lua/config.lua index 04d5cda1e704..36be2b6b121e 100644 --- a/stand/lua/config.lua +++ b/stand/lua/config.lua @@ -1,812 +1,882 @@ -- -- SPDX-License-Identifier: BSD-2-Clause-FreeBSD -- -- Copyright (c) 2015 Pedro Souza -- Copyright (c) 2018 Kyle Evans -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- -- $FreeBSD$ -- local hook = require("hook") local config = {} local modules = {} local carousel_choices = {} -- Which variables we changed local env_changed = {} -- Values to restore env to (nil to unset) local env_restore = {} local MSG_FAILDIR = "Failed to load conf dir '%s': not a directory" local MSG_FAILEXEC = "Failed to exec '%s'" local MSG_FAILSETENV = "Failed to '%s' with value: %s" local MSG_FAILOPENCFG = "Failed to open config: '%s'" local MSG_FAILREADCFG = "Failed to read config: '%s'" local MSG_FAILPARSECFG = "Failed to parse config: '%s'" +local MSG_FAILEXECLUA = "Failed to execute lua conf '%s': '%s'" local MSG_FAILPARSEVAR = "Failed to parse variable '%s': %s" local MSG_FAILEXBEF = "Failed to execute '%s' before loading '%s'" local MSG_FAILEXAF = "Failed to execute '%s' after loading '%s'" local MSG_MALFORMED = "Malformed line (%d):\n\t'%s'" local MSG_DEFAULTKERNFAIL = "No kernel set, failed to load from module_path" local MSG_KERNFAIL = "Failed to load kernel '%s'" local MSG_XENKERNFAIL = "Failed to load Xen kernel '%s'" local MSG_XENKERNLOADING = "Loading Xen kernel..." local MSG_KERNLOADING = "Loading kernel..." local MSG_MODLOADING = "Loading configured modules..." local MSG_MODBLACKLIST = "Not loading blacklisted module '%s'" local MSG_FAILSYN_QUOTE = "Stray quote at position '%d'" local MSG_FAILSYN_EOLESC = "Stray escape at end of line" local MSG_FAILSYN_EOLVAR = "Unescaped $ at end of line" local MSG_FAILSYN_BADVAR = "Malformed variable expression at position '%d'" local MODULEEXPR = '([-%w_]+)' local QVALEXPR = '"(.*)"' local QVALREPL = QVALEXPR:gsub('%%', '%%%%') local WORDEXPR = "([-%w%d][-%w%d_.]*)" local WORDREPL = WORDEXPR:gsub('%%', '%%%%') -- Entries that should never make it into the environment; each one should have -- a documented reason for its existence, and these should all be implementation -- details of the config module. local loader_env_restricted_table = { -- loader_conf_files should be considered write-only, and consumers -- should not rely on any particular value; it's a loader implementation -- detail. Moreover, it's not a particularly useful variable to have in -- the kenv. Save the overhead, let it get fetched other ways. loader_conf_files = true, } local function restoreEnv() -- Examine changed environment variables for k, v in pairs(env_changed) do local restore_value = env_restore[k] if restore_value == nil then -- This one doesn't need restored for some reason goto continue end local current_value = loader.getenv(k) if current_value ~= v then -- This was overwritten by some action taken on the menu -- most likely; we'll leave it be. goto continue end restore_value = restore_value.value if restore_value ~= nil then loader.setenv(k, restore_value) else loader.unsetenv(k) end ::continue:: end env_changed = {} env_restore = {} end -- XXX This getEnv/setEnv should likely be exported at some point. We can save -- the call back into loader.getenv for any variable that's been set or -- overridden by any loader.conf using this implementation with little overhead -- since we're already tracking the values. local function getEnv(key) if loader_env_restricted_table[key] ~= nil or env_changed[key] ~= nil then return env_changed[key] end return loader.getenv(key) end local function setEnv(key, value) env_changed[key] = value if loader_env_restricted_table[key] ~= nil then return 0 end -- Track the original value for this if we haven't already if env_restore[key] == nil then env_restore[key] = {value = loader.getenv(key)} end return loader.setenv(key, value) end -- name here is one of 'name', 'type', flags', 'before', 'after', or 'error.' -- These are set from lines in loader.conf(5): ${key}_${name}="${value}" where -- ${key} is a module name. local function setKey(key, name, value) if modules[key] == nil then modules[key] = {} end modules[key][name] = value end -- Escapes the named value for use as a literal in a replacement pattern. -- e.g. dhcp.host-name gets turned into dhcp%.host%-name to remove the special -- meaning. local function escapeName(name) return name:gsub("([%p])", "%%%1") end local function processEnvVar(value) local pval, vlen = '', #value local nextpos, vdelim, vinit = 1 local vpat for i = 1, vlen do if i < nextpos then goto nextc end local c = value:sub(i, i) if c == '\\' then if i == vlen then return nil, MSG_FAILSYN_EOLESC end nextpos = i + 2 pval = pval .. value:sub(i + 1, i + 1) elseif c == '"' then return nil, MSG_FAILSYN_QUOTE:format(i) elseif c == "$" then if i == vlen then return nil, MSG_FAILSYN_EOLVAR else if value:sub(i + 1, i + 1) == "{" then -- Skip ${ vinit = i + 2 vdelim = '}' vpat = "^([^}]+)}" else -- Skip the $ vinit = i + 1 vdelim = nil vpat = "^([%w][-%w%d_.]*)" end local name = value:match(vpat, vinit) if not name then return nil, MSG_FAILSYN_BADVAR:format(i) else nextpos = vinit + #name if vdelim then nextpos = nextpos + 1 end local repl = loader.getenv(name) or "" pval = pval .. repl end end else pval = pval .. c end ::nextc:: end return pval end local function checkPattern(line, pattern) local function _realCheck(_line, _pattern) return _line:match(_pattern) end if pattern:find('$VALUE') then local k, v, c k, v, c = _realCheck(line, pattern:gsub('$VALUE', QVALREPL)) if k ~= nil then return k,v, c end return _realCheck(line, pattern:gsub('$VALUE', WORDREPL)) else return _realCheck(line, pattern) end end -- str in this table is a regex pattern. It will automatically be anchored to -- the beginning of a line and any preceding whitespace will be skipped. The -- pattern should have no more than two captures patterns, which correspond to -- the two parameters (usually 'key' and 'value') that are passed to the -- process function. All trailing characters will be validated. Any $VALUE -- token included in a pattern will be tried first with a quoted value capture -- group, then a single-word value capture group. This is our kludge for Lua -- regex not supporting branching. -- -- We have two special entries in this table: the first is the first entry, -- a full-line comment. The second is for 'exec' handling. Both have a single -- capture group, but the difference is that the full-line comment pattern will -- match the entire line. This does not run afoul of the later end of line -- validation that we'll do after a match. However, the 'exec' pattern will. -- We document the exceptions with a special 'groups' index that indicates -- the number of capture groups, if not two. We'll use this later to do -- validation on the proper entry. -- local pattern_table = { { + luaexempt = true, str = "(#.*)", process = function(_, _) end, groups = 1, }, -- module_load="value" { - str = MODULEEXPR .. "_load%s*=%s*$VALUE", + name = MODULEEXPR .. "_load%s*", + val = "%s*$VALUE", process = function(k, v) if modules[k] == nil then modules[k] = {} end modules[k].load = v:upper() setEnv(k .. "_load", v:upper()) end, }, -- module_name="value" { - str = MODULEEXPR .. "_name%s*=%s*$VALUE", + name = MODULEEXPR .. "_name%s*", + val = "%s*$VALUE", process = function(k, v) setKey(k, "name", v) setEnv(k .. "_name", v) end, }, -- module_type="value" { - str = MODULEEXPR .. "_type%s*=%s*$VALUE", + name = MODULEEXPR .. "_type%s*", + val = "%s*$VALUE", process = function(k, v) setKey(k, "type", v) setEnv(k .. "_type", v) end, }, -- module_flags="value" { - str = MODULEEXPR .. "_flags%s*=%s*$VALUE", + name = MODULEEXPR .. "_flags%s*", + val = "%s*$VALUE", process = function(k, v) setKey(k, "flags", v) setEnv(k .. "_flags", v) end, }, -- module_before="value" { - str = MODULEEXPR .. "_before%s*=%s*$VALUE", + name = MODULEEXPR .. "_before%s*", + val = "%s*$VALUE", process = function(k, v) setKey(k, "before", v) setEnv(k .. "_before", v) end, }, -- module_after="value" { - str = MODULEEXPR .. "_after%s*=%s*$VALUE", + name = MODULEEXPR .. "_after%s*", + val = "%s*$VALUE", process = function(k, v) setKey(k, "after", v) setEnv(k .. "_after", v) end, }, -- module_error="value" { - str = MODULEEXPR .. "_error%s*=%s*$VALUE", + name = MODULEEXPR .. "_error%s*", + val = "%s*$VALUE", process = function(k, v) setKey(k, "error", v) setEnv(k .. "_error", v) end, }, -- exec="command" { - str = "exec%s*=%s*" .. QVALEXPR, + luaexempt = true, + name = "exec%s*", + val = "%s*" .. QVALEXPR, process = function(k, _) if cli_execute_unparsed(k) ~= 0 then print(MSG_FAILEXEC:format(k)) end end, groups = 1, }, -- env_var="value" or env_var=[word|num] { - str = "([%w][%w%d-_.]*)%s*=%s*$VALUE", + name = "([%w][%w%d-_.]*)%s*", + val = "%s*$VALUE", process = function(k, v) local pv, msg = processEnvVar(v) if not pv then print(MSG_FAILPARSEVAR:format(k, msg)) return end if setEnv(k, pv) ~= 0 then print(MSG_FAILSETENV:format(k, v)) + else + return pv end end, }, } local function isValidComment(line) if line ~= nil then local s = line:match("^%s*#.*") if s == nil then s = line:match("^%s*$") end if s == nil then return false end end return true end local function getBlacklist() local blacklist = {} local blacklist_str = loader.getenv('module_blacklist') if blacklist_str == nil then return blacklist end for mod in blacklist_str:gmatch("[;, ]?([-%w_]+)[;, ]?") do blacklist[mod] = true end return blacklist end local function loadModule(mod, silent) local status = true local blacklist = getBlacklist() local pstatus for k, v in pairs(mod) do if v.load ~= nil and v.load:lower() == "yes" then local module_name = v.name or k if not v.force and blacklist[module_name] ~= nil then if not silent then print(MSG_MODBLACKLIST:format(module_name)) end goto continue end if not silent then loader.printc(module_name .. "...") end local str = "load " if v.type ~= nil then str = str .. "-t " .. v.type .. " " end str = str .. module_name if v.flags ~= nil then str = str .. " " .. v.flags end if v.before ~= nil then pstatus = cli_execute_unparsed(v.before) == 0 if not pstatus and not silent then print(MSG_FAILEXBEF:format(v.before, k)) end status = status and pstatus end if cli_execute_unparsed(str) ~= 0 then -- XXX Temporary shim: don't break the boot if -- loader hadn't been recompiled with this -- function exposed. if loader.command_error then print(loader.command_error()) end if not silent then print("failed!") end if v.error ~= nil then cli_execute_unparsed(v.error) end status = false elseif v.after ~= nil then pstatus = cli_execute_unparsed(v.after) == 0 if not pstatus and not silent then print(MSG_FAILEXAF:format(v.after, k)) end if not silent then print("ok") end status = status and pstatus end end ::continue:: end return status end local function readFile(name, silent) local f = io.open(name) if f == nil then if not silent then print(MSG_FAILOPENCFG:format(name)) end return nil end local text, _ = io.read(f) -- We might have read in the whole file, this won't be needed any more. io.close(f) if text == nil and not silent then print(MSG_FAILREADCFG:format(name)) end return text end local function checkNextboot() local nextboot_file = loader.getenv("nextboot_conf") local nextboot_enable = loader.getenv("nextboot_enable") if nextboot_file == nil then return end -- is nextboot_enable set in nvstore? if nextboot_enable == "NO" then return end local text = readFile(nextboot_file, true) if text == nil then return end if nextboot_enable == nil and text:match("^nextboot_enable=\"NO\"") ~= nil then -- We're done; nextboot is not enabled return end if not config.parse(text) then print(MSG_FAILPARSECFG:format(nextboot_file)) end -- Attempt to rewrite the first line and only the first line of the -- nextboot_file. We overwrite it with nextboot_enable="NO", then -- check for that on load. -- It's worth noting that this won't work on every filesystem, so we -- won't do anything notable if we have any errors in this process. local nfile = io.open(nextboot_file, 'w') if nfile ~= nil then -- We need the trailing space here to account for the extra -- character taken up by the string nextboot_enable="YES" -- Or new end quotation mark lands on the S, and we want to -- rewrite the entirety of the first line. io.write(nfile, "nextboot_enable=\"NO\" ") io.close(nfile) end loader.setenv("nextboot_enable", "NO") end +local function processEnv(k, v) + for _, val in ipairs(pattern_table) do + if not val.luaexempt and val.name then + local matched = k:match(val.name) + + if matched then + return val.process(matched, v) + end + end + end +end + -- Module exports config.verbose = false -- The first item in every carousel is always the default item. function config.getCarouselIndex(id) return carousel_choices[id] or 1 end function config.setCarouselIndex(id, idx) carousel_choices[id] = idx end -- Returns true if we processed the file successfully, false if we did not. -- If 'silent' is true, being unable to read the file is not considered a -- failure. function config.processFile(name, silent) if silent == nil then silent = false end local text = readFile(name, silent) if text == nil then return silent end - return config.parse(text) + if name:match(".lua$") then + local cfg_env = setmetatable({}, { + indices = {}, + __index = function(env, key) + if getmetatable(env).indices[key] then + return rawget(env, key) + end + + return loader.getenv(key) + end, + __newindex = function(env, key, val) + getmetatable(env).indices[key] = true + rawset(env, key, val) + end, + }) + + -- Give local modules a chance to populate the config + -- environment. + hook.runAll("config.buildenv", cfg_env) + local res, err = pcall(load(text, name, "t", cfg_env)) + if res then + for k, v in pairs(cfg_env) do + local t = type(v) + if t ~= "function" and t ~= "table" then + if t ~= "string" then + v = tostring(v) + end + local pval = processEnv(k, v) + if pval then + setEnv(k, pval) + end + end + end + else + print(MSG_FAILEXECLUA:format(name, err)) + end + + return res + else + return config.parse(text) + end end -- silent runs will not return false if we fail to open the file function config.parse(text) local n = 1 local status = true for line in text:gmatch("([^\n]+)") do if line:match("^%s*$") == nil then for _, val in ipairs(pattern_table) do + if val.str == nil then + val.str = val.name .. "=" .. val.val + end local pattern = '^%s*' .. val.str .. '%s*(.*)'; local cgroups = val.groups or 2 local k, v, c = checkPattern(line, pattern) if k ~= nil then -- Offset by one, drats if cgroups == 1 then c = v v = nil end if isValidComment(c) then val.process(k, v) goto nextline end break end end print(MSG_MALFORMED:format(n, line)) status = false end ::nextline:: n = n + 1 end return status end function config.readConf(file, loaded_files) if loaded_files == nil then loaded_files = {} end if loaded_files[file] ~= nil then return end -- We'll process loader_conf_dirs at the top-level readConf local load_conf_dirs = next(loaded_files) == nil print("Loading " .. file) -- The final value of loader_conf_files is not important, so just -- clobber it here. We'll later check if it's no longer nil and process -- the new value for files to read. setEnv("loader_conf_files", nil) -- These may or may not exist, and that's ok. Do a -- silent parse so that we complain on parse errors but -- not for them simply not existing. if not config.processFile(file, true) then print(MSG_FAILPARSECFG:format(file)) end loaded_files[file] = true -- Going to process "loader_conf_files" extra-files local loader_conf_files = getEnv("loader_conf_files") if loader_conf_files ~= nil then for name in loader_conf_files:gmatch("[%w%p]+") do config.readConf(name, loaded_files) end end if load_conf_dirs then local loader_conf_dirs = getEnv("loader_conf_dirs") if loader_conf_dirs ~= nil then for name in loader_conf_dirs:gmatch("[%w%p]+") do if lfs.attributes(name, "mode") ~= "directory" then print(MSG_FAILDIR:format(name)) goto nextdir end for cfile in lfs.dir(name) do if cfile:match(".conf$") then local fpath = name .. "/" .. cfile if lfs.attributes(fpath, "mode") == "file" then config.readConf(fpath, loaded_files) end end end ::nextdir:: end end end end -- other_kernel is optionally the name of a kernel to load, if not the default -- or autoloaded default from the module_path function config.loadKernel(other_kernel) local flags = loader.getenv("kernel_options") or "" local kernel = other_kernel or loader.getenv("kernel") local function tryLoad(names) for name in names:gmatch("([^;]+)%s*;?") do local r = loader.perform("load " .. name .. " " .. flags) if r == 0 then return name end end return nil end local function getModulePath() local module_path = loader.getenv("module_path") local kernel_path = loader.getenv("kernel_path") if kernel_path == nil then return module_path end -- Strip the loaded kernel path from module_path. This currently assumes -- that the kernel path will be prepended to the module_path when it's -- found. kernel_path = escapeName(kernel_path .. ';') return module_path:gsub(kernel_path, '') end local function loadBootfile() local bootfile = loader.getenv("bootfile") -- append default kernel name if bootfile == nil then bootfile = "kernel" else bootfile = bootfile .. ";kernel" end return tryLoad(bootfile) end -- kernel not set, try load from default module_path if kernel == nil then local res = loadBootfile() if res ~= nil then -- Default kernel is loaded config.kernel_loaded = nil return true else print(MSG_DEFAULTKERNFAIL) return false end else -- Use our cached module_path, so we don't end up with multiple -- automatically added kernel paths to our final module_path local module_path = getModulePath() local res if other_kernel ~= nil then kernel = other_kernel end -- first try load kernel with module_path = /boot/${kernel} -- then try load with module_path=${kernel} local paths = {"/boot/" .. kernel, kernel} for _, v in pairs(paths) do loader.setenv("module_path", v) res = loadBootfile() -- succeeded, add path to module_path if res ~= nil then config.kernel_loaded = kernel if module_path ~= nil then loader.setenv("module_path", v .. ";" .. module_path) loader.setenv("kernel_path", v) end return true end end -- failed to load with ${kernel} as a directory -- try as a file res = tryLoad(kernel) if res ~= nil then config.kernel_loaded = kernel return true else print(MSG_KERNFAIL:format(kernel)) return false end end end function config.selectKernel(kernel) config.kernel_selected = kernel end function config.load(file, reloading) if not file then file = "/boot/defaults/loader.conf" end config.readConf(file) checkNextboot() local verbose = loader.getenv("verbose_loading") or "no" config.verbose = verbose:lower() == "yes" if not reloading then hook.runAll("config.loaded") end end -- Reload configuration function config.reload(file) modules = {} restoreEnv() config.load(file, true) hook.runAll("config.reloaded") end function config.loadelf() local xen_kernel = loader.getenv('xen_kernel') local kernel = config.kernel_selected or config.kernel_loaded local status if xen_kernel ~= nil then print(MSG_XENKERNLOADING) if cli_execute_unparsed('load ' .. xen_kernel) ~= 0 then print(MSG_XENKERNFAIL:format(xen_kernel)) return false end end print(MSG_KERNLOADING) if not config.loadKernel(kernel) then return false end hook.runAll("kernel.loaded") print(MSG_MODLOADING) status = loadModule(modules, not config.verbose) hook.runAll("modules.loaded") return status end function config.enableModule(modname) if modules[modname] == nil then modules[modname] = {} elseif modules[modname].load == "YES" then modules[modname].force = true return true end modules[modname].load = "YES" modules[modname].force = true return true end function config.disableModule(modname) if modules[modname] == nil then return false elseif modules[modname].load ~= "YES" then return true end modules[modname].load = "NO" modules[modname].force = nil return true end function config.isModuleEnabled(modname) local mod = modules[modname] if not mod or mod.load ~= "YES" then return false end if mod.force then return true end local blacklist = getBlacklist() return not blacklist[modname] end function config.getModuleInfo() return { modules = modules, blacklist = getBlacklist() } end +hook.registerType("config.buildenv") hook.registerType("config.loaded") hook.registerType("config.reloaded") hook.registerType("kernel.loaded") hook.registerType("modules.loaded") return config diff --git a/stand/lua/config.lua.8 b/stand/lua/config.lua.8 index 4fc51c90045f..cf4316204008 100644 --- a/stand/lua/config.lua.8 +++ b/stand/lua/config.lua.8 @@ -1,236 +1,244 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD .\" .\" Copyright (c) 2018 Kyle Evans .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd December 17, 2020 .Dt CONFIG.LUA 8 .Os .Sh NAME .Nm config.lua .Nd FreeBSD config module .Sh DESCRIPTION .Nm contains configuration and module loading functionality. .Pp Before hooking into or using the functionality provided by .Nm , it must be included with a statement such as the following: .Pp .Dl local config = require("config") .Ss Exported functions The following functions are exported from .Nm : .Bl -tag -width "config.setCarouselIndex(id, idx)" -offset indent .It Fn config.getCarouselIndex id Returns the currently chosen index in the carousel menu entry described by .Ev id . See the definition of .Xr menu.lua 8 for a more in-depth explanation of carousels. .It Fn config.setCarouselIndex id idx Set the chosen index for the carousel menu entry described by .Ev id to .Ev idx . A lookup will be done as needed to determine what value .Ev idx actually corresponds to. .It Fn config.readConf file loaded_files Process .Pa file as a configuration file .Po e.g., as .Pa loader.conf .Pc and then processing files listed in .Ev loader_conf_files variable .Po see .Xr loader.conf 5 .Pc . The caller may optionally pass in a table as the .Ev loaded_files argument, which uses filenames as keys and any non-nil value to indicate that the file named by the key has already been loaded and should not be loaded again. .It Fn config.processFile name silent Process and parse .Ev name as a configuration file. Returns true if .Ev name exists and parses without error, false otherwise. If .Ev silent is true, .Fn config.processFile will not consider a failure to read the file as a failure. .It Fn config.parse text Parse .Ev text as a configuration file. This is used internally by .Fn config.processFile to parse the contents of a configuration file. Returns true if parsing succeeds without error, false if an error occurred. A message is also printed to the console if an error is encountered. .It Fn config.loadKernel other_kernel Attempts to load .Ev other_kernel as a kernel. If .Ev other_kernel is unset .Fn config.loadKernel will attempt to load .Dq kernel . Otherwise, it will try to load .Dq kernel first from .Pa /boot/{other_kernel} , then from .Pa {other_kernel} . .Pp The latter is tried in case an absolute path has been specified to the kernel to use. .Ev module_path is amended to include the directory the kernel was found in if either of these paths result in a loaded kernel. .Pp If no kernel was loaded from either of these paths, .Fn config.loadKernel will attempt to load a kernel named .Dq {other_kernel} from .Ev module_path instead of attempting to load a kernel named .Dq kernel . .Pp Returns true if a kernel was loaded, false if no kernel was loaded. .It Fn config.selectKernel kernel Set .Ev kernel to the kernel that will be loaded when either .Ic autoboot or .Ic boot are invoked. This is usually called by the menu system as the kernel selector carousel is toggled through. .It Fn config.load file reload Loads .Ev file as a configuration file. If .Ev file is not specified, .Pa /boot/defaults/loader.conf is used. .Fn config.load will then silently attempt to process any files specified in .Ev loader_conf_files after .Ev file has been processed. .Xr nextboot 8 configuration will also be checked as part of .Fn config.load . Before returning, all .Dq config.loaded hooks will be run if .Ev reload is not set to true. .It Fn config.reload file Reloads .Ev file as a configuration file. .Fn config.reload will restore the environment to how it existed before the last config was loaded, then it will invoke .Fn config.load file . Before returning, all .Dq config.reloaded hooks will be run. .It Fn config.loadelf Loads all ELF objects, the selected kernel as well as any modules configured to be preloaded in .Xr loader.conf 5 . This will be called by the Lua intercepted .Ic autoboot and .Ic boot commands. .It Fn config.enableModule modname Marks a module named .Fa modname to be loaded during .Fn config.loadelf . If the module was previously blacklisted, then it will be forcefully allowed to load. .It Fn config.disableModule modname Marks a module named .Fa modname to not be loaded during .Fn config.loadelf . .It Fn config.isModuleEnabled modname Checks if the module named .Fa modname will be loaded during .Fn config.loadelf . It checks both that the module is marked for loading and that it is either forced or not blacklisted. .It Fn config.getModuleInfo Returns a table with .Dq modules and .Dq blacklist tables describing the modules that the config module has been made aware of via .Xr loader.conf 5 as well as a representation of .Ar module_blacklist . .El .Ss Defined Hooks The following hooks are defined in .Nm : .Bl -tag -width "config.reloaded" -offset indent +.It Fn config.buildenv env .It Fn config.loaded .It Fn config.reloaded .It Fn kernel.loaded .It Fn modules.loaded .El +.Pp +Note that the +.Fn config.buildenv +hook is only invoked when an environment needs to be built to execute a lua +configuration file that has been specified in +.Ev loader_conf_files . +It will be invoked for each configuration file encountered. .Sh SEE ALSO .Xr loader.conf 5 , .Xr loader 8 , .Xr menu.lua 8 , .Xr nextboot 8 .Sh AUTHORS The .Nm file was originally written by .An Pedro Souza Aq Mt pedrosouza@FreeBSD.org . Later work and this manual page was done by .An Kyle Evans Aq Mt kevans@FreeBSD.org . diff --git a/stand/lua/hook.lua b/stand/lua/hook.lua index 9c7e4deeb7e4..6826bcb5f7f1 100644 --- a/stand/lua/hook.lua +++ b/stand/lua/hook.lua @@ -1,83 +1,83 @@ -- -- SPDX-License-Identifier: BSD-2-Clause-FreeBSD -- -- Copyright (c) 2018 Kyle Evans -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- 1. Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- 2. Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- SUCH DAMAGE. -- -- $FreeBSD$ -- local hook = {} local registered_hooks = {} -- Module exports -- Register a hook type; these are the names that hooks may be registered for. -- It is expected that modules will register all of their hook types upon -- initial load. Other modules may then, at any time, register a hook for these -- types. -- -- Naming convention: hook types should be sensible named, preferably prefixed -- with the name of the module that registered them. They would also ideally -- describe an action that may or may not match a function name. -- e.g. config.reloaded which takes place after config has been reloaded, -- possibly from a different source. function hook.registerType(hooktype) registered_hooks[hooktype] = {} end function hook.register(hooktype, hookfunc) local selected_hooks = registered_hooks[hooktype] if selected_hooks == nil then print("Tried registering a hook for an unknown hook type: " .. hooktype) return end selected_hooks[#selected_hooks + 1] = hookfunc registered_hooks[hooktype] = selected_hooks end -- Takes a hooktype and runs all functions associated with that specific hook -- type in the order that they were registered in. This ordering should likely -- not be relied upon. -function hook.runAll(hooktype) +function hook.runAll(hooktype, data) local selected_hooks = registered_hooks[hooktype] if selected_hooks == nil then -- This message, and the print() above, should only be seen by -- developers. Hook type registration should have happened at -- module load, so if this hasn't happened then we have messed -- up the order in which we've loaded modules and we need to -- catch that as soon as possible. print("Tried to run hooks for an unknown hook type: " .. hooktype) return 0 end if #selected_hooks > 0 then for _, func in ipairs(selected_hooks) do - func() + func(data) end end return #selected_hooks end return hook diff --git a/stand/lua/hook.lua.8 b/stand/lua/hook.lua.8 index 1bc9ca96b509..f53d643d79bd 100644 --- a/stand/lua/hook.lua.8 +++ b/stand/lua/hook.lua.8 @@ -1,94 +1,96 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD .\" .\" Copyright (c) 2018 Kyle Evans .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd June 9, 2018 +.Dd April 28, 2020 .Dt HOOK.LUA 8 .Os .Sh NAME .Nm hook.lua .Nd FreeBSD hook module .Sh DESCRIPTION .Nm contains functionality for defining hook types and attaching hooks. Hooks are functions used to attach custom behaviors at pre-defined points in loader execution. These pre-defined points are what we refer to as .Dq hook types . +Hooks may also take an optional data parameter, which may or may not be +populated by the caller. .Pp Before using the functionality provided by .Nm , it must be included with a statement such as the following: .Pp .Dl local hook = require("hook") .Ss Exported functions The following functions are exported from .Nm : .Bl -tag -width hook.registerType -offset indent .It Fn hook.registerType hooktype Adds .Ev hooktype as a recognized hook type. This allows functions to be added to run when hooks of this type are invoked using .Fn hook.runAll hooktype . .It Fn hook.register hooktype hookfunc Register .Ev hookfunc to be run when hooks of type .Ev hooktype are invoked. .It Fn hook.runAll hooktype Invoke all hooks registered for type .Ev hooktype . Hooks are invoked in the order in which they are registered. .El .Ss Hook Naming Guidelines Hook names should consist of the name of the module they are defined in, as well as a verb describing when the hook is executed, separated by a period. For example, .Dq config.reloaded is defined in the .Xr config.lua 8 module and run when the configuration is reloaded. .Sh EXAMPLES To register a hook to be run when configuration is reloaded: .Pp .Bd -literal -offset indent -compact local hook = require("hook") local function configuration_was_reloaded() print("Configuration was reloaded!") end hook.register("config.reloaded", configuration_was_reloaded) .Ed .Sh AUTHORS The .Nm file was originally written by .An Kyle Evans Aq Mt kevans@FreeBSD.org . diff --git a/stand/lua/loader.conf.lua.5 b/stand/lua/loader.conf.lua.5 new file mode 100644 index 000000000000..5c8938c321f9 --- /dev/null +++ b/stand/lua/loader.conf.lua.5 @@ -0,0 +1,77 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD +.\" +.\" Copyright (c) 2020 Kyle Evans +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd May 10, 2023 +.Dt LOADER.CONF.LUA 5 +.Os +.Sh NAME +.Nm loader.conf.lua +.Nd Lua-based system bootstrap configuration file +.Sh DESCRIPTION +When the lua-based +.Xr loader 8 +encounters a filename in +.Va loader_conf_files +that has a +.Dq .lua +suffix, it will be loaded and executed by the lua interpreter in a limited +environment. +.Pp +The limited environment does not contain the ability to reference or load other +lua modules. +Existing loader environment variables may be referenced as if they were already +defined global variables. +.Pp +A lua configuration file may set any global variable, which will subsequently +be processed and added to the environment after execution of the configuration +file has completed. +Other than the +.Ar exec +setting, all variables described in +.Xr loader.conf 5 +operate the same in the +.Nm +environment. +Note that the settings describing module options can only be set in the +environment; there is currently no way for a +.Pa loader.conf.lua +to fetch them. +At this time, global table and function values are ignored. +.Pp +The +.Fn config.buildenv +hook will be run with an empty environment provided to it that may be populated +by a custom +.Pa local.lua . +.Sh SEE ALSO +.Xr loader.conf 5 +.Sh AUTHORS +The mechanism for loading +.Nm +files was originally written by +.An Kyle Evans Aq Mt kevans@FreeBSD.org .