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()
71 caridx = (caridx % #choices) + 1
72 config.setCarouselIndex(carid, caridx)
73 entry.func(caridx, choices[caridx], choices)
76 [core.MENU_SUBMENU] = function(current_menu, entry)
78 return menu.run(entry.submenu)
80 [core.MENU_RETURN] = function(current_menu, entry)
81 -- allow entry to have a function/side effect
82 if entry.func ~= nil then
88 -- loader menu tree is rooted at menu.welcome
92 -- return to welcome menu
94 entry_type = core.MENU_RETURN,
96 return "Back to main menu" ..
97 color.highlight(" [Backspace]")
103 entry_type = core.MENU_ENTRY,
105 return "Load System " .. color.highlight("D") ..
115 entry_type = core.MENU_SEPARATOR,
119 entry_type = core.MENU_SEPARATOR,
121 return "Boot Options:"
127 entry_type = core.MENU_ENTRY,
128 visible = core.isSystem386,
130 return OnOff(color.highlight("A") ..
140 entry_type = core.MENU_ENTRY,
142 return OnOff("Safe " .. color.highlight("M") ..
152 entry_type = core.MENU_ENTRY,
154 return OnOff(color.highlight("S") ..
155 "ingle user:", core.su)
164 entry_type = core.MENU_ENTRY,
166 return OnOff(color.highlight("V") ..
167 "erbose :", core.verbose)
179 local menu_entries = menu.welcome.all_entries
180 -- Swap the first two menu items on single user boot
181 if core.isSingleUserBoot() then
182 -- We'll cache the swapped menu, for performance
183 if menu.welcome.swapped_menu ~= nil then
184 return menu.welcome.swapped_menu
186 -- Shallow copy the table
187 menu_entries = core.shallowCopyTable(menu_entries)
189 -- Swap the first two menu entries
190 menu_entries[1], menu_entries[2] =
191 menu_entries[2], menu_entries[1]
193 -- Then set their names to their alternate names
194 menu_entries[1].name, menu_entries[2].name =
195 menu_entries[1].alternate_name,
196 menu_entries[2].alternate_name
197 menu.welcome.swapped_menu = menu_entries
204 entry_type = core.MENU_ENTRY,
206 return color.highlight("B") ..
208 color.highlight("[Enter]")
210 -- Not a standard menu entry function!
211 alternate_name = function()
212 return color.highlight("B") ..
216 core.setSingleUser(false)
224 entry_type = core.MENU_ENTRY,
226 return "Boot " .. color.highlight("S") ..
229 -- Not a standard menu entry function!
230 alternate_name = function()
231 return "Boot " .. color.highlight("S") ..
232 "ingle user " .. color.highlight("[Enter]")
235 core.setSingleUser(true)
241 -- escape to interpreter
243 entry_type = core.MENU_RETURN,
245 return color.highlight("Esc") ..
246 "ape to loader prompt"
249 loader.setenv("autoboot_delay", "NO")
251 alias = {core.KEYSTR_ESCAPE}
256 entry_type = core.MENU_ENTRY,
258 return color.highlight("R") .. "eboot"
261 loader.perform("reboot")
268 entry_type = core.MENU_SEPARATOR,
272 entry_type = core.MENU_SEPARATOR,
280 entry_type = core.MENU_CAROUSEL_ENTRY,
281 carousel_id = "kernel",
282 items = core.kernelList,
283 name = function(idx, choice, all_choices)
284 if #all_choices == 0 then
288 local is_default = (idx == 1)
289 local kernel_name = ""
292 name_color = color.escapef(color.GREEN)
293 kernel_name = "default/"
295 name_color = color.escapef(color.BLUE)
297 kernel_name = kernel_name .. name_color ..
298 choice .. color.default()
299 return color.highlight("K") .. "ernel: " ..
300 kernel_name .. " (" .. idx .. " of " ..
303 func = function(idx, choice, all_choices)
304 config.selectkernel(choice)
311 entry_type = core.MENU_SUBMENU,
313 return "Boot " .. color.highlight("O") ..
316 submenu = menu.boot_options,
322 menu.default = menu.welcome
338 local alias_table = drawer.drawscreen(m)
344 local key = io.getchar()
346 -- Special key behaviors
347 if (key == core.KEY_BACKSPACE or key == core.KEY_DELETE) and
348 m ~= menu.default then
350 elseif key == core.KEY_ENTER then
355 key = string.char(key)
356 -- check to see if key is an alias
357 local sel_entry = nil
358 for k, v in pairs(alias_table) do
364 -- if we have an alias do the assigned action:
365 if sel_entry ~= nil then
367 local handler = menu.handlers[sel_entry.entry_type]
368 if handler ~= nil then
369 -- The handler's return value indicates whether
370 -- we need to exit this menu. An omitted return
371 -- value means "continue" by default.
372 cont = handler(m, sel_entry)
377 -- if we got an alias key the screen is out of date:
380 alias_table = drawer.drawscreen(m)
384 if m == menu.default then
386 print("Exiting menu!")
394 if core.isSerialBoot() then
397 local c = string.lower(loader.getenv("console") or "")
398 if c:match("^efi[ ;]") ~= nil or c:match("[ ;]efi[ ;]") ~= nil then
402 c = string.lower(loader.getenv("beastie_disable") or "")
403 print("beastie_disable", c)
407 function menu.autoboot()
408 if menu.already_autoboot then
411 menu.already_autoboot = true
413 local ab = loader.getenv("autoboot_delay")
414 if ab ~= nil and ab:lower() == "no" then
416 elseif tonumber(ab) == -1 then
419 ab = tonumber(ab) or 10
421 local x = loader.getenv("loader_menu_timeout_x") or 5
422 local y = loader.getenv("loader_menu_timeout_y") or 22
424 local endtime = loader.time() + ab
428 time = endtime - loader.time()
429 screen.setcursor(x, y)
430 print("Autoboot in " .. time ..
431 " seconds, hit [Enter] to boot" ..
432 " or any other key to stop ")
435 local ch = io.getchar()
436 if ch == core.KEY_ENTER then
439 -- erase autoboot msg
440 screen.setcursor(0, y)