xref: /freebsd/stand/lua/menu.lua (revision ca16d83fd4b5267c042fd740fc928b46e3ceb77b)
1088b4f5fSWarner Losh--
272e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
372e39d71SKyle Evans--
4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
521d5bcbeSKyle Evans-- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org>
6088b4f5fSWarner Losh-- All rights reserved.
7088b4f5fSWarner Losh--
8088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without
9088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions
10088b4f5fSWarner Losh-- are met:
11088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright
12088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer.
13088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright
14088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer in the
15088b4f5fSWarner Losh--    documentation and/or other materials provided with the distribution.
16088b4f5fSWarner Losh--
17088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20088b4f5fSWarner Losh-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27088b4f5fSWarner Losh-- SUCH DAMAGE.
28088b4f5fSWarner Losh--
29088b4f5fSWarner Losh-- $FreeBSD$
30088b4f5fSWarner Losh--
31088b4f5fSWarner Losh
32088b4f5fSWarner Losh
33aedd6be5SKyle Evanslocal core = require("core")
34aedd6be5SKyle Evanslocal color = require("color")
35aedd6be5SKyle Evanslocal config = require("config")
36aedd6be5SKyle Evanslocal screen = require("screen")
37aedd6be5SKyle Evanslocal drawer = require("drawer")
38088b4f5fSWarner Losh
39aedd6be5SKyle Evanslocal menu = {}
40c8518398SKyle Evans
41*ca16d83fSKyle Evanslocal screen_invalid = true
42*ca16d83fSKyle Evans
439ed6f9efSKyle Evanslocal function OnOff(str, b)
449f71d421SKyle Evans	if b then
45e15abd1fSKyle Evans		return str .. color.escapef(color.GREEN) .. "On" ..
46aedd6be5SKyle Evans		    color.escapef(color.WHITE)
47e15abd1fSKyle Evans	else
48e15abd1fSKyle Evans		return str .. color.escapef(color.RED) .. "off" ..
49aedd6be5SKyle Evans		    color.escapef(color.WHITE)
50e15abd1fSKyle Evans	end
51e15abd1fSKyle Evansend
52e15abd1fSKyle Evans
539ed6f9efSKyle Evanslocal function bootenvSet(env)
547efc058fSKyle Evans	loader.setenv("vfs.root.mountfrom", env)
557efc058fSKyle Evans	loader.setenv("currdev", env .. ":")
567efc058fSKyle Evans	config.reload()
577efc058fSKyle Evansend
587efc058fSKyle Evans
59b5746545SKyle Evans-- Module exports
608d415029SKyle Evansmenu.handlers = {
618d415029SKyle Evans	-- Menu handlers take the current menu and selected entry as parameters,
628d415029SKyle Evans	-- and should return a boolean indicating whether execution should
638d415029SKyle Evans	-- continue or not. The return value may be omitted if this entry should
648d415029SKyle Evans	-- have no bearing on whether we continue or not, indicating that we
658d415029SKyle Evans	-- should just continue after execution.
66e2df27e3SKyle Evans	[core.MENU_ENTRY] = function(_, entry)
678d415029SKyle Evans		-- run function
68aedd6be5SKyle Evans		entry.func()
698d415029SKyle Evans	end,
70e2df27e3SKyle Evans	[core.MENU_CAROUSEL_ENTRY] = function(_, entry)
718d415029SKyle Evans		-- carousel (rotating) functionality
72aedd6be5SKyle Evans		local carid = entry.carousel_id
73aedd6be5SKyle Evans		local caridx = config.getCarouselIndex(carid)
744f437f9eSKyle Evans		local choices = entry.items
754f437f9eSKyle Evans		if type(choices) == "function" then
764f437f9eSKyle Evans			choices = choices()
774f437f9eSKyle Evans		end
789f71d421SKyle Evans		if #choices > 0 then
79aedd6be5SKyle Evans			caridx = (caridx % #choices) + 1
80aedd6be5SKyle Evans			config.setCarouselIndex(carid, caridx)
81aedd6be5SKyle Evans			entry.func(caridx, choices[caridx], choices)
828d415029SKyle Evans		end
838d415029SKyle Evans	end,
84e2df27e3SKyle Evans	[core.MENU_SUBMENU] = function(_, entry)
85*ca16d83fSKyle Evans		screen_invalid = true
86da9ab827SKyle Evans		menu.process(entry.submenu)
878d415029SKyle Evans	end,
88e2df27e3SKyle Evans	[core.MENU_RETURN] = function(_, entry)
898d415029SKyle Evans		-- allow entry to have a function/side effect
909f71d421SKyle Evans		if entry.func ~= nil then
91aedd6be5SKyle Evans			entry.func()
928d415029SKyle Evans		end
93aedd6be5SKyle Evans		return false
948d415029SKyle Evans	end,
95aedd6be5SKyle Evans}
96280e990bSKyle Evans-- loader menu tree is rooted at menu.welcome
97088b4f5fSWarner Losh
987efc058fSKyle Evansmenu.boot_environments = {
997efc058fSKyle Evans	entries = {
1007efc058fSKyle Evans		-- return to welcome menu
1017efc058fSKyle Evans		{
1027efc058fSKyle Evans			entry_type = core.MENU_RETURN,
1037efc058fSKyle Evans			name = "Back to main menu" ..
1047efc058fSKyle Evans			    color.highlight(" [Backspace]"),
1057efc058fSKyle Evans		},
1067efc058fSKyle Evans		{
1077efc058fSKyle Evans			entry_type = core.MENU_CAROUSEL_ENTRY,
1087efc058fSKyle Evans			carousel_id = "be_active",
1097efc058fSKyle Evans			items = core.bootenvList,
1107efc058fSKyle Evans			name = function(idx, choice, all_choices)
1117efc058fSKyle Evans				if #all_choices == 0 then
1127efc058fSKyle Evans					return "Active: "
1137efc058fSKyle Evans				end
1147efc058fSKyle Evans
1157efc058fSKyle Evans				local is_default = (idx == 1)
1167efc058fSKyle Evans				local bootenv_name = ""
1177efc058fSKyle Evans				local name_color
1187efc058fSKyle Evans				if is_default then
1197efc058fSKyle Evans					name_color = color.escapef(color.GREEN)
1207efc058fSKyle Evans				else
1217efc058fSKyle Evans					name_color = color.escapef(color.BLUE)
1227efc058fSKyle Evans				end
1237efc058fSKyle Evans				bootenv_name = bootenv_name .. name_color ..
1247efc058fSKyle Evans				    choice .. color.default()
1257efc058fSKyle Evans				return color.highlight("A").."ctive: " ..
1267efc058fSKyle Evans				    bootenv_name .. " (" .. idx .. " of " ..
1277efc058fSKyle Evans				    #all_choices .. ")"
1287efc058fSKyle Evans			end,
129e2df27e3SKyle Evans			func = function(_, choice, _)
1307efc058fSKyle Evans				bootenvSet(choice)
1317efc058fSKyle Evans			end,
1327efc058fSKyle Evans			alias = {"a", "A"},
1337efc058fSKyle Evans		},
1347efc058fSKyle Evans		{
1357efc058fSKyle Evans			entry_type = core.MENU_ENTRY,
1367efc058fSKyle Evans			name = function()
1377efc058fSKyle Evans				return color.highlight("b") .. "ootfs: " ..
1387efc058fSKyle Evans				    core.bootenvDefault()
1397efc058fSKyle Evans			end,
1407efc058fSKyle Evans			func = function()
1417efc058fSKyle Evans				-- Reset active boot environment to the default
1427efc058fSKyle Evans				config.setCarouselIndex("be_active", 1)
1437efc058fSKyle Evans				bootenvSet(core.bootenvDefault())
1447efc058fSKyle Evans			end,
1457efc058fSKyle Evans			alias = {"b", "B"},
1467efc058fSKyle Evans		},
1477efc058fSKyle Evans	},
1487efc058fSKyle Evans}
1497efc058fSKyle Evans
150088b4f5fSWarner Loshmenu.boot_options = {
151d8757746SKyle Evans	entries = {
152088b4f5fSWarner Losh		-- return to welcome menu
153088b4f5fSWarner Losh		{
154a7cf0562SKyle Evans			entry_type = core.MENU_RETURN,
155a51f9f0cSKyle Evans			name = "Back to main menu" ..
156a51f9f0cSKyle Evans			    color.highlight(" [Backspace]"),
157088b4f5fSWarner Losh		},
158088b4f5fSWarner Losh		-- load defaults
159088b4f5fSWarner Losh		{
160a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
161a51f9f0cSKyle Evans			name = "Load System " .. color.highlight("D") ..
162a51f9f0cSKyle Evans			    "efaults",
163a51f9f0cSKyle Evans			func = core.setDefaults,
1643cd5547bSKyle Evans			alias = {"d", "D"},
165088b4f5fSWarner Losh		},
166088b4f5fSWarner Losh		{
167a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
168088b4f5fSWarner Losh		},
169088b4f5fSWarner Losh		{
170a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
171a51f9f0cSKyle Evans			name = "Boot Options:",
172088b4f5fSWarner Losh		},
173088b4f5fSWarner Losh		-- acpi
174088b4f5fSWarner Losh		{
175a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
176c1ab36f5SKyle Evans			visible = core.isSystem386,
177088b4f5fSWarner Losh			name = function()
178fd2b19b3SKyle Evans				return OnOff(color.highlight("A") ..
179aedd6be5SKyle Evans				    "CPI       :", core.acpi)
180088b4f5fSWarner Losh			end,
181a51f9f0cSKyle Evans			func = core.setACPI,
1823cd5547bSKyle Evans			alias = {"a", "A"},
183088b4f5fSWarner Losh		},
184088b4f5fSWarner Losh		-- safe mode
185088b4f5fSWarner Losh		{
186a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
187088b4f5fSWarner Losh			name = function()
18857099121SKyle Evans				return OnOff("Safe " .. color.highlight("M") ..
189aedd6be5SKyle Evans				    "ode  :", core.sm)
190088b4f5fSWarner Losh			end,
191a51f9f0cSKyle Evans			func = core.setSafeMode,
1923cd5547bSKyle Evans			alias = {"m", "M"},
193088b4f5fSWarner Losh		},
194088b4f5fSWarner Losh		-- single user
195088b4f5fSWarner Losh		{
196a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
197088b4f5fSWarner Losh			name = function()
198fd2b19b3SKyle Evans				return OnOff(color.highlight("S") ..
199aedd6be5SKyle Evans				    "ingle user:", core.su)
200088b4f5fSWarner Losh			end,
201a51f9f0cSKyle Evans			func = core.setSingleUser,
2023cd5547bSKyle Evans			alias = {"s", "S"},
203088b4f5fSWarner Losh		},
204088b4f5fSWarner Losh		-- verbose boot
205088b4f5fSWarner Losh		{
206a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
207088b4f5fSWarner Losh			name = function()
208fd2b19b3SKyle Evans				return OnOff(color.highlight("V") ..
209aedd6be5SKyle Evans				    "erbose    :", core.verbose)
210088b4f5fSWarner Losh			end,
211a51f9f0cSKyle Evans			func = core.setVerbose,
2123cd5547bSKyle Evans			alias = {"v", "V"},
213088b4f5fSWarner Losh		},
214d8757746SKyle Evans	},
215aedd6be5SKyle Evans}
216088b4f5fSWarner Losh
217088b4f5fSWarner Loshmenu.welcome = {
218303253e5SKyle Evans	entries = function()
219aedd6be5SKyle Evans		local menu_entries = menu.welcome.all_entries
220303253e5SKyle Evans		-- Swap the first two menu items on single user boot
2219f71d421SKyle Evans		if core.isSingleUserBoot() then
2229a0904b0SKyle Evans			-- We'll cache the swapped menu, for performance
2239f71d421SKyle Evans			if menu.welcome.swapped_menu ~= nil then
224aedd6be5SKyle Evans				return menu.welcome.swapped_menu
2259a0904b0SKyle Evans			end
2265c1b5165SKyle Evans			-- Shallow copy the table
227ee4e69f1SKyle Evans			menu_entries = core.deepCopyTable(menu_entries)
2285c1b5165SKyle Evans
2299a0904b0SKyle Evans			-- Swap the first two menu entries
2304b6da14cSKyle Evans			menu_entries[1], menu_entries[2] =
231aedd6be5SKyle Evans			    menu_entries[2], menu_entries[1]
232303253e5SKyle Evans
2339a0904b0SKyle Evans			-- Then set their names to their alternate names
2349a0904b0SKyle Evans			menu_entries[1].name, menu_entries[2].name =
2359a0904b0SKyle Evans			    menu_entries[1].alternate_name,
236aedd6be5SKyle Evans			    menu_entries[2].alternate_name
237aedd6be5SKyle Evans			menu.welcome.swapped_menu = menu_entries
238303253e5SKyle Evans		end
239aedd6be5SKyle Evans		return menu_entries
240303253e5SKyle Evans	end,
241303253e5SKyle Evans	all_entries = {
242088b4f5fSWarner Losh		-- boot multi user
243088b4f5fSWarner Losh		{
244a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
245a51f9f0cSKyle Evans			name = color.highlight("B") .. "oot Multi user " ..
246a51f9f0cSKyle Evans			    color.highlight("[Enter]"),
2475c1b5165SKyle Evans			-- Not a standard menu entry function!
248a51f9f0cSKyle Evans			alternate_name = color.highlight("B") ..
249a51f9f0cSKyle Evans			    "oot Multi user",
250088b4f5fSWarner Losh			func = function()
251aedd6be5SKyle Evans				core.setSingleUser(false)
252aedd6be5SKyle Evans				core.boot()
253088b4f5fSWarner Losh			end,
2543cd5547bSKyle Evans			alias = {"b", "B"},
255088b4f5fSWarner Losh		},
256088b4f5fSWarner Losh		-- boot single user
257088b4f5fSWarner Losh		{
258a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
259a51f9f0cSKyle Evans			name = "Boot " .. color.highlight("S") .. "ingle user",
2605c1b5165SKyle Evans			-- Not a standard menu entry function!
261a51f9f0cSKyle Evans			alternate_name = "Boot " .. color.highlight("S") ..
262a51f9f0cSKyle Evans			    "ingle user " .. color.highlight("[Enter]"),
263088b4f5fSWarner Losh			func = function()
264aedd6be5SKyle Evans				core.setSingleUser(true)
265aedd6be5SKyle Evans				core.boot()
266088b4f5fSWarner Losh			end,
2673cd5547bSKyle Evans			alias = {"s", "S"},
268088b4f5fSWarner Losh		},
269088b4f5fSWarner Losh		-- escape to interpreter
270088b4f5fSWarner Losh		{
271a7cf0562SKyle Evans			entry_type = core.MENU_RETURN,
272a51f9f0cSKyle Evans			name = color.highlight("Esc") .. "ape to loader prompt",
273ef625845SKyle Evans			func = function()
274aedd6be5SKyle Evans				loader.setenv("autoboot_delay", "NO")
275ef625845SKyle Evans			end,
2763cd5547bSKyle Evans			alias = {core.KEYSTR_ESCAPE},
277088b4f5fSWarner Losh		},
278088b4f5fSWarner Losh		-- reboot
279088b4f5fSWarner Losh		{
280a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
281a51f9f0cSKyle Evans			name = color.highlight("R") .. "eboot",
282088b4f5fSWarner Losh			func = function()
283aedd6be5SKyle Evans				loader.perform("reboot")
284088b4f5fSWarner Losh			end,
2853cd5547bSKyle Evans			alias = {"r", "R"},
286088b4f5fSWarner Losh		},
287088b4f5fSWarner Losh		{
288a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
289088b4f5fSWarner Losh		},
290088b4f5fSWarner Losh		{
291a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
292a51f9f0cSKyle Evans			name = "Options:",
293088b4f5fSWarner Losh		},
294088b4f5fSWarner Losh		-- kernel options
295088b4f5fSWarner Losh		{
296a7cf0562SKyle Evans			entry_type = core.MENU_CAROUSEL_ENTRY,
297ada26c4aSKyle Evans			carousel_id = "kernel",
298ada26c4aSKyle Evans			items = core.kernelList,
299ada26c4aSKyle Evans			name = function(idx, choice, all_choices)
3009f71d421SKyle Evans				if #all_choices == 0 then
301aedd6be5SKyle Evans					return "Kernel: "
302088b4f5fSWarner Losh				end
303b1b1f2b8SKyle Evans
304aedd6be5SKyle Evans				local is_default = (idx == 1)
305aedd6be5SKyle Evans				local kernel_name = ""
306aedd6be5SKyle Evans				local name_color
3079f71d421SKyle Evans				if is_default then
308aedd6be5SKyle Evans					name_color = color.escapef(color.GREEN)
309aedd6be5SKyle Evans					kernel_name = "default/"
310bcf48a15SKyle Evans				else
311aedd6be5SKyle Evans					name_color = color.escapef(color.BLUE)
312b1b1f2b8SKyle Evans				end
313fd2b19b3SKyle Evans				kernel_name = kernel_name .. name_color ..
314aedd6be5SKyle Evans				    choice .. color.default()
315fd2b19b3SKyle Evans				return color.highlight("K") .. "ernel: " ..
316fd2b19b3SKyle Evans				    kernel_name .. " (" .. idx .. " of " ..
317aedd6be5SKyle Evans				    #all_choices .. ")"
318088b4f5fSWarner Losh			end,
319e2df27e3SKyle Evans			func = function(_, choice, _)
320322a2dddSKyle Evans				config.selectKernel(choice)
321088b4f5fSWarner Losh			end,
3223cd5547bSKyle Evans			alias = {"k", "K"},
323088b4f5fSWarner Losh		},
324088b4f5fSWarner Losh		-- boot options
325088b4f5fSWarner Losh		{
326a7cf0562SKyle Evans			entry_type = core.MENU_SUBMENU,
327a51f9f0cSKyle Evans			name = "Boot " .. color.highlight("O") .. "ptions",
3289a28f948SKyle Evans			submenu = menu.boot_options,
3293cd5547bSKyle Evans			alias = {"o", "O"},
330d8757746SKyle Evans		},
3317efc058fSKyle Evans		-- boot environments
3327efc058fSKyle Evans		{
3337efc058fSKyle Evans			entry_type = core.MENU_SUBMENU,
3347efc058fSKyle Evans			visible = function()
3357efc058fSKyle Evans				return core.isZFSBoot() and
3367efc058fSKyle Evans				    #core.bootenvList() > 1
3377efc058fSKyle Evans			end,
3387efc058fSKyle Evans			name = "Boot " .. color.highlight("E") .. "nvironments",
3397efc058fSKyle Evans			submenu = menu.boot_environments,
3407efc058fSKyle Evans			alias = {"e", "E"},
3417efc058fSKyle Evans		},
342d8757746SKyle Evans	},
343aedd6be5SKyle Evans}
344088b4f5fSWarner Losh
34520a81676SKyle Evansmenu.default = menu.welcome
34628384160SKyle Evans-- current_alias_table will be used to keep our alias table consistent across
34728384160SKyle Evans-- screen redraws, instead of relying on whatever triggered the redraw to update
34828384160SKyle Evans-- the local alias_table in menu.process.
34928384160SKyle Evansmenu.current_alias_table = {}
35020a81676SKyle Evans
35128384160SKyle Evansfunction menu.redraw(m)
352088b4f5fSWarner Losh	-- redraw screen
353aedd6be5SKyle Evans	screen.clear()
354aedd6be5SKyle Evans	screen.defcursor()
35528384160SKyle Evans	menu.current_alias_table = drawer.drawscreen(m)
356*ca16d83fSKyle Evans	screen_invalid = false
35728384160SKyle Evansend
35828384160SKyle Evans
359*ca16d83fSKyle Evans-- 'keypress' allows the caller to indicate that a key has been pressed that we
360*ca16d83fSKyle Evans-- should process as our initial input.
361*ca16d83fSKyle Evansfunction menu.process(m, keypress)
36228384160SKyle Evans	assert(m ~= nil)
36328384160SKyle Evans
364*ca16d83fSKyle Evans	-- Trigger a redraw if we've been invalidated.  Otherwise, we assume
365*ca16d83fSKyle Evans	-- that this menu has already been drawn.
366*ca16d83fSKyle Evans	if screen_invalid then
36728384160SKyle Evans		menu.redraw(m)
3687dcffa90SKyle Evans	end
369*ca16d83fSKyle Evans
370da9ab827SKyle Evans	while true do
371*ca16d83fSKyle Evans		local key = keypress or io.getchar()
372*ca16d83fSKyle Evans		keypress = nil
373088b4f5fSWarner Losh
374b458bf0dSKyle Evans		-- Special key behaviors
3759f71d421SKyle Evans		if (key == core.KEY_BACKSPACE or key == core.KEY_DELETE) and
37620a81676SKyle Evans		    m ~= menu.default then
377aedd6be5SKyle Evans			break
3789f71d421SKyle Evans		elseif key == core.KEY_ENTER then
379aedd6be5SKyle Evans			core.boot()
380b458bf0dSKyle Evans			-- Should not return
381abc4f7e7SKyle Evans		end
382abc4f7e7SKyle Evans
383abc4f7e7SKyle Evans		key = string.char(key)
384088b4f5fSWarner Losh		-- check to see if key is an alias
385aedd6be5SKyle Evans		local sel_entry = nil
38628384160SKyle Evans		for k, v in pairs(menu.current_alias_table) do
3879f71d421SKyle Evans			if key == k then
388aedd6be5SKyle Evans				sel_entry = v
38928384160SKyle Evans				break
390088b4f5fSWarner Losh			end
391088b4f5fSWarner Losh		end
392088b4f5fSWarner Losh
393088b4f5fSWarner Losh		-- if we have an alias do the assigned action:
3949f71d421SKyle Evans		if sel_entry ~= nil then
3958d415029SKyle Evans			-- Get menu handler
396aedd6be5SKyle Evans			local handler = menu.handlers[sel_entry.entry_type]
3979f71d421SKyle Evans			if handler ~= nil then
398da9ab827SKyle Evans				-- The handler's return value indicates if we
399da9ab827SKyle Evans				-- need to exit this menu.  An omitted or true
400da9ab827SKyle Evans				-- return value means to continue.
401da9ab827SKyle Evans				if handler(m, sel_entry) == false then
402da9ab827SKyle Evans					return
403aefcaa7eSKyle Evans				end
404088b4f5fSWarner Losh			end
40528384160SKyle Evans			-- If we got an alias key the screen is out of date...
40628384160SKyle Evans			-- redraw it.
40728384160SKyle Evans			menu.redraw(m)
408088b4f5fSWarner Losh		end
409088b4f5fSWarner Losh	end
410088b4f5fSWarner Loshend
411088b4f5fSWarner Losh
412da9ab827SKyle Evansfunction menu.run()
413da9ab827SKyle Evans	if menu.skip() then
414da9ab827SKyle Evans		core.autoboot()
415da9ab827SKyle Evans		return
416da9ab827SKyle Evans	end
417da9ab827SKyle Evans
418*ca16d83fSKyle Evans	menu.redraw(menu.default)
419*ca16d83fSKyle Evans	local autoboot_key = menu.autoboot()
420*ca16d83fSKyle Evans
421*ca16d83fSKyle Evans	menu.process(menu.default, autoboot_key)
422da9ab827SKyle Evans
423da9ab827SKyle Evans	screen.defcursor()
424da9ab827SKyle Evans	print("Exiting menu!")
425088b4f5fSWarner Loshend
426088b4f5fSWarner Losh
427088b4f5fSWarner Loshfunction menu.skip()
4289f71d421SKyle Evans	if core.isSerialBoot() then
429aedd6be5SKyle Evans		return true
430088b4f5fSWarner Losh	end
431aedd6be5SKyle Evans	local c = string.lower(loader.getenv("console") or "")
4329f71d421SKyle Evans	if c:match("^efi[ ;]") ~= nil or c:match("[ ;]efi[ ;]") ~= nil then
433aedd6be5SKyle Evans		return true
434088b4f5fSWarner Losh	end
435088b4f5fSWarner Losh
436aedd6be5SKyle Evans	c = string.lower(loader.getenv("beastie_disable") or "")
437aedd6be5SKyle Evans	print("beastie_disable", c)
438aedd6be5SKyle Evans	return c == "yes"
439088b4f5fSWarner Loshend
440088b4f5fSWarner Losh
441088b4f5fSWarner Loshfunction menu.autoboot()
442aedd6be5SKyle Evans	local ab = loader.getenv("autoboot_delay")
4439f71d421SKyle Evans	if ab ~= nil and ab:lower() == "no" then
44412b95c84SKyle Evans		return nil
4459f71d421SKyle Evans	elseif tonumber(ab) == -1 then
446aedd6be5SKyle Evans		core.boot()
447088b4f5fSWarner Losh	end
448aedd6be5SKyle Evans	ab = tonumber(ab) or 10
449088b4f5fSWarner Losh
450aedd6be5SKyle Evans	local x = loader.getenv("loader_menu_timeout_x") or 5
451aedd6be5SKyle Evans	local y = loader.getenv("loader_menu_timeout_y") or 22
452088b4f5fSWarner Losh
453aedd6be5SKyle Evans	local endtime = loader.time() + ab
454aedd6be5SKyle Evans	local time
455088b4f5fSWarner Losh
456088b4f5fSWarner Losh	repeat
457aedd6be5SKyle Evans		time = endtime - loader.time()
458aedd6be5SKyle Evans		screen.setcursor(x, y)
45957099121SKyle Evans		print("Autoboot in " .. time ..
46057099121SKyle Evans		    " seconds, hit [Enter] to boot" ..
461aedd6be5SKyle Evans		    " or any other key to stop     ")
462aedd6be5SKyle Evans		screen.defcursor()
4639f71d421SKyle Evans		if io.ischar() then
464aedd6be5SKyle Evans			local ch = io.getchar()
4659f71d421SKyle Evans			if ch == core.KEY_ENTER then
466aedd6be5SKyle Evans				break
467088b4f5fSWarner Losh			else
468088b4f5fSWarner Losh				-- erase autoboot msg
469aedd6be5SKyle Evans				screen.setcursor(0, y)
47066964bbcSKyle Evans				print(string.rep(" ", 80))
471aedd6be5SKyle Evans				screen.defcursor()
47212b95c84SKyle Evans				return ch
473088b4f5fSWarner Losh			end
474088b4f5fSWarner Losh		end
475088b4f5fSWarner Losh
476aedd6be5SKyle Evans		loader.delay(50000)
477aedd6be5SKyle Evans	until time <= 0
478aedd6be5SKyle Evans	core.boot()
479088b4f5fSWarner Losh
480088b4f5fSWarner Loshend
481088b4f5fSWarner Losh
482aedd6be5SKyle Evansreturn menu
483