2 -- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3 -- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org>
4 -- All rights reserved.
6 -- Redistribution and use in source and binary forms, with or without
7 -- modification, are permitted provided that the following conditions
9 -- 1. Redistributions of source code must retain the above copyright
10 -- notice, this list of conditions and the following disclaimer.
11 -- 2. Redistributions in binary form must reproduce the above copyright
12 -- notice, this list of conditions and the following disclaimer in the
13 -- documentation and/or other materials provided with the distribution.
15 -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 local carousel_choices = {}
40 process = function(k, v) end
42 -- module_load="value"
44 str = "^%s*([%w_]+)_load%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
45 process = function(k, v)
46 if modules[k] == nil then
49 modules[k].load = v:upper()
52 -- module_name="value"
54 str = "^%s*([%w_]+)_name%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
55 process = function(k, v)
56 config.setKey(k, "name", v)
59 -- module_type="value"
61 str = "^%s*([%w_]+)_type%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
62 process = function(k, v)
63 config.setKey(k, "type", v)
66 -- module_flags="value"
68 str = "^%s*([%w_]+)_flags%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
69 process = function(k, v)
70 config.setKey(k, "flags", v)
73 -- module_before="value"
75 str = "^%s*([%w_]+)_before%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
76 process = function(k, v)
77 config.setKey(k, "before", v)
80 -- module_after="value"
82 str = "^%s*([%w_]+)_after%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
83 process = function(k, v)
84 config.setKey(k, "after", v)
87 -- module_error="value"
89 str = "^%s*([%w_]+)_error%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
90 process = function(k, v)
91 config.setKey(k, "error", v)
96 str = "^%s*exec%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
97 process = function(k, v)
98 if loader.perform(k) ~= 0 then
99 print("Failed to exec '" .. k .. "'")
105 str = "^%s*([%w%p]+)%s*=%s*\"([%w%s%p]-)\"%s*(.*)",
106 process = function(k, v)
107 if config.setenv(k, v) ~= 0 then
108 print("Failed to set '" .. k ..
109 "' with value: " .. v .. "")
115 str = "^%s*([%w%p]+)%s*=%s*(%d+)%s*(.*)",
116 process = function(k, v)
117 if config.setenv(k, v) ~= 0 then
118 print("Failed to set '" .. k ..
119 "' with value: " .. v .. "")
126 -- Which variables we changed
127 config.env_changed = {}
128 -- Values to restore env to (nil to unset)
129 config.env_restore = {}
131 -- The first item in every carousel is always the default item.
132 function config.getCarouselIndex(id)
133 local val = carousel_choices[id]
140 function config.setCarouselIndex(id, idx)
141 carousel_choices[id] = idx
144 function config.restoreEnv()
145 -- Examine changed environment variables
146 for k, v in pairs(config.env_changed) do
147 local restore_value = config.env_restore[k]
148 if restore_value == nil then
149 -- This one doesn't need restored for some reason
152 local current_value = loader.getenv(k)
153 if current_value ~= v then
154 -- This was overwritten by some action taken on the menu
155 -- most likely; we'll leave it be.
158 restore_value = restore_value.value
159 if restore_value ~= nil then
160 loader.setenv(k, restore_value)
167 config.env_changed = {}
168 config.env_restore = {}
171 function config.setenv(k, v)
172 -- Track the original value for this if we haven't already
173 if config.env_restore[k] == nil then
174 config.env_restore[k] = {value = loader.getenv(k)}
177 config.env_changed[k] = v
179 return loader.setenv(k, v)
182 function config.setKey(k, n, v)
183 if modules[k] == nil then
189 function config.lsModules()
190 print("== Listing modules")
191 for k, v in pairs(modules) do
194 print("== List of modules ended")
198 function config.isValidComment(c)
200 local s = c:match("^%s*#.*")
211 function config.loadmod(mod, silent)
213 for k, v in pairs(mod) do
214 if v.load == "YES" then
216 if v.flags ~= nil then
217 str = str .. v.flags .. " "
219 if v.type ~= nil then
220 str = str .. "-t " .. v.type .. " "
222 if v.name ~= nil then
228 if v.before ~= nil then
229 if loader.perform(v.before) ~= 0 then
231 print("Failed to execute '" ..
233 "' before loading '" .. k ..
240 if loader.perform(str) ~= 0 then
242 print("Failed to execute '" .. str ..
245 if v.error ~= nil then
246 loader.perform(v.error)
251 if v.after ~= nil then
252 if loader.perform(v.after) ~= 0 then
254 print("Failed to execute '" ..
256 "' after loading '" .. k ..
264 -- if not silent then
265 -- print("Skipping module '". . k .. "'")
273 -- silent runs will not return false if we fail to open the file
274 function config.parse(name, silent)
275 if silent == nil then
278 local f = io.open(name)
281 print("Failed to open config: '" .. name .. "'")
293 print("Failed to read config: '" .. name .. "'")
301 for line in text:gmatch("([^\n]+)") do
302 if line:match("^%s*$") == nil then
305 for i, val in ipairs(pattern_table) do
306 local k, v, c = line:match(val.str)
310 if config.isValidComment(c) then
313 print("Malformed line (" .. n ..
314 "):\n\t'" .. line .. "'")
323 print("Malformed line (" .. n .. "):\n\t'" ..
334 -- other_kernel is optionally the name of a kernel to load, if not the default
335 -- or autoloaded default from the module_path
336 function config.loadkernel(other_kernel)
337 local flags = loader.getenv("kernel_options") or ""
338 local kernel = other_kernel or loader.getenv("kernel")
340 local try_load = function (names)
341 for name in names:gmatch("([^;]+)%s*;?") do
342 r = loader.perform("load " .. flags .. " " .. name)
350 local load_bootfile = function()
351 local bootfile = loader.getenv("bootfile")
353 -- append default kernel name
354 if bootfile == nil then
357 bootfile = bootfile .. ";kernel"
360 return try_load(bootfile)
363 -- kernel not set, try load from default module_path
364 if kernel == nil then
365 local res = load_bootfile()
368 -- Default kernel is loaded
369 config.kernel_loaded = nil
372 print("No kernel set, failed to load from module_path")
376 -- Use our cached module_path, so we don't end up with multiple
377 -- automatically added kernel paths to our final module_path
378 local module_path = config.module_path
381 if other_kernel ~= nil then
382 kernel = other_kernel
384 -- first try load kernel with module_path = /boot/${kernel}
385 -- then try load with module_path=${kernel}
386 local paths = {"/boot/" .. kernel, kernel}
388 for k,v in pairs(paths) do
389 loader.setenv("module_path", v)
390 res = load_bootfile()
392 -- succeeded, add path to module_path
394 config.kernel_loaded = kernel
395 if module_path ~= nil then
396 loader.setenv("module_path", v .. ";" ..
403 -- failed to load with ${kernel} as a directory
405 res = try_load(kernel)
407 config.kernel_loaded = kernel
410 print("Failed to load kernel '" .. kernel .. "'")
416 function config.selectkernel(kernel)
417 config.kernel_selected = kernel
420 function config.load(file)
422 file = "/boot/defaults/loader.conf"
425 if not config.parse(file) then
426 print("Failed to parse configuration: '" .. file .. "'")
429 local f = loader.getenv("loader_conf_files")
431 for name in f:gmatch("([%w%p]+)%s*") do
432 -- These may or may not exist, and that's ok. Do a
433 -- silent parse so that we complain on parse errors but
434 -- not for them simply not existing.
435 if not config.parse(name, true) then
436 print("Failed to parse configuration: '" ..
442 -- Cache the provided module_path at load time for later use
443 config.module_path = loader.getenv("module_path")
446 -- Reload configuration
447 function config.reload(file)
453 function config.loadelf()
454 local kernel = config.kernel_selected or config.kernel_loaded
457 print("Loading kernel...")
458 loaded = config.loadkernel(kernel)
461 print("Failed to load any kernel")
465 print("Loading configured modules...")
466 if not config.loadmod(modules) then
467 print("Could not load one or more modules!")