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
31 local core = require("core")
32 local color = require("color")
33 local config = require("config")
34 local screen = require("screen")
35 local drawer = require("drawer")
43 local OnOff = function(str, b)
45 return str .. color.escapef(color.GREEN) .. "On" ..
46 color.escapef(color.WHITE)
48 return str .. color.escapef(color.RED) .. "off" ..
49 color.escapef(color.WHITE)
55 -- Menu handlers take the current menu and selected entry as parameters,
56 -- and should return a boolean indicating whether execution should
57 -- continue or not. The return value may be omitted if this entry should
58 -- have no bearing on whether we continue or not, indicating that we
59 -- should just continue after execution.
60 [core.MENU_ENTRY] = function(current_menu, entry)
64 [core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry)
65 -- carousel (rotating) functionality
66 local carid = entry.carousel_id
67 local caridx = config.getCarouselIndex(carid)
68 local choices = entry.items
69 if type(choices) == "function" then
73 caridx = (caridx % #choices) + 1
74 config.setCarouselIndex(carid, caridx)
75 entry.func(caridx, choices[caridx], choices)
78 [core.MENU_SUBMENU] = function(current_menu, entry)
80 return menu.run(entry.submenu)
82 [core.MENU_RETURN] = function(current_menu, entry)
83 -- allow entry to have a function/side effect
84 if entry.func ~= nil then
90 -- loader menu tree is rooted at menu.welcome
94 -- return to welcome menu
96 entry_type = core.MENU_RETURN,
97 name = "Back to main menu" ..
98 color.highlight(" [Backspace]"),
102 entry_type = core.MENU_ENTRY,
103 name = "Load System " .. color.highlight("D") ..
105 func = core.setDefaults,
109 entry_type = core.MENU_SEPARATOR,
112 entry_type = core.MENU_SEPARATOR,
113 name = "Boot Options:",
117 entry_type = core.MENU_ENTRY,
118 visible = core.isSystem386,
120 return OnOff(color.highlight("A") ..
128 entry_type = core.MENU_ENTRY,
130 return OnOff("Safe " .. color.highlight("M") ..
133 func = core.setSafeMode,
138 entry_type = core.MENU_ENTRY,
140 return OnOff(color.highlight("S") ..
141 "ingle user:", core.su)
143 func = core.setSingleUser,
148 entry_type = core.MENU_ENTRY,
150 return OnOff(color.highlight("V") ..
151 "erbose :", core.verbose)
153 func = core.setVerbose,
161 local menu_entries = menu.welcome.all_entries
162 -- Swap the first two menu items on single user boot
163 if core.isSingleUserBoot() then
164 -- We'll cache the swapped menu, for performance
165 if menu.welcome.swapped_menu ~= nil then
166 return menu.welcome.swapped_menu
168 -- Shallow copy the table
169 menu_entries = core.shallowCopyTable(menu_entries)
171 -- Swap the first two menu entries
172 menu_entries[1], menu_entries[2] =
173 menu_entries[2], menu_entries[1]
175 -- Then set their names to their alternate names
176 menu_entries[1].name, menu_entries[2].name =
177 menu_entries[1].alternate_name,
178 menu_entries[2].alternate_name
179 menu.welcome.swapped_menu = menu_entries
186 entry_type = core.MENU_ENTRY,
187 name = color.highlight("B") .. "oot Multi user " ..
188 color.highlight("[Enter]"),
189 -- Not a standard menu entry function!
190 alternate_name = color.highlight("B") ..
193 core.setSingleUser(false)
200 entry_type = core.MENU_ENTRY,
201 name = "Boot " .. color.highlight("S") .. "ingle user",
202 -- Not a standard menu entry function!
203 alternate_name = "Boot " .. color.highlight("S") ..
204 "ingle user " .. color.highlight("[Enter]"),
206 core.setSingleUser(true)
211 -- escape to interpreter
213 entry_type = core.MENU_RETURN,
214 name = color.highlight("Esc") .. "ape to loader prompt",
216 loader.setenv("autoboot_delay", "NO")
218 alias = {core.KEYSTR_ESCAPE}
222 entry_type = core.MENU_ENTRY,
223 name = color.highlight("R") .. "eboot",
225 loader.perform("reboot")
230 entry_type = core.MENU_SEPARATOR,
233 entry_type = core.MENU_SEPARATOR,
238 entry_type = core.MENU_CAROUSEL_ENTRY,
239 carousel_id = "kernel",
240 items = core.kernelList,
241 name = function(idx, choice, all_choices)
242 if #all_choices == 0 then
246 local is_default = (idx == 1)
247 local kernel_name = ""
250 name_color = color.escapef(color.GREEN)
251 kernel_name = "default/"
253 name_color = color.escapef(color.BLUE)
255 kernel_name = kernel_name .. name_color ..
256 choice .. color.default()
257 return color.highlight("K") .. "ernel: " ..
258 kernel_name .. " (" .. idx .. " of " ..
261 func = function(idx, choice, all_choices)
262 config.selectkernel(choice)
268 entry_type = core.MENU_SUBMENU,
269 name = "Boot " .. color.highlight("O") .. "ptions",
270 submenu = menu.boot_options,
276 menu.default = menu.welcome
292 local alias_table = drawer.drawscreen(m)
294 -- Might return nil, that's ok
295 local autoboot_key = menu.autoboot()
299 local key = autoboot_key or io.getchar()
302 -- Special key behaviors
303 if (key == core.KEY_BACKSPACE or key == core.KEY_DELETE) and
304 m ~= menu.default then
306 elseif key == core.KEY_ENTER then
311 key = string.char(key)
312 -- check to see if key is an alias
313 local sel_entry = nil
314 for k, v in pairs(alias_table) do
320 -- if we have an alias do the assigned action:
321 if sel_entry ~= nil then
323 local handler = menu.handlers[sel_entry.entry_type]
324 if handler ~= nil then
325 -- The handler's return value indicates whether
326 -- we need to exit this menu. An omitted return
327 -- value means "continue" by default.
328 cont = handler(m, sel_entry)
333 -- if we got an alias key the screen is out of date:
336 alias_table = drawer.drawscreen(m)
340 if m == menu.default then
342 print("Exiting menu!")
350 if core.isSerialBoot() then
353 local c = string.lower(loader.getenv("console") or "")
354 if c:match("^efi[ ;]") ~= nil or c:match("[ ;]efi[ ;]") ~= nil then
358 c = string.lower(loader.getenv("beastie_disable") or "")
359 print("beastie_disable", c)
363 function menu.autoboot()
364 if menu.already_autoboot then
367 menu.already_autoboot = true
369 local ab = loader.getenv("autoboot_delay")
370 if ab ~= nil and ab:lower() == "no" then
372 elseif tonumber(ab) == -1 then
375 ab = tonumber(ab) or 10
377 local x = loader.getenv("loader_menu_timeout_x") or 5
378 local y = loader.getenv("loader_menu_timeout_y") or 22
380 local endtime = loader.time() + ab
384 time = endtime - loader.time()
385 screen.setcursor(x, y)
386 print("Autoboot in " .. time ..
387 " seconds, hit [Enter] to boot" ..
388 " or any other key to stop ")
391 local ch = io.getchar()
392 if ch == core.KEY_ENTER then
395 -- erase autoboot msg
396 screen.setcursor(0, y)