xref: /freebsd/stand/lua/menu.lua (revision 4f437f9eab22fa9ba21dbcabe253e13de5dde71d)
1088b4f5fSWarner Losh--
2088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
321d5bcbeSKyle Evans-- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org>
4088b4f5fSWarner Losh-- All rights reserved.
5088b4f5fSWarner Losh--
6088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without
7088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions
8088b4f5fSWarner Losh-- are met:
9088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright
10088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer.
11088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright
12088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer in the
13088b4f5fSWarner Losh--    documentation and/or other materials provided with the distribution.
14088b4f5fSWarner Losh--
15088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18088b4f5fSWarner Losh-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25088b4f5fSWarner Losh-- SUCH DAMAGE.
26088b4f5fSWarner Losh--
27088b4f5fSWarner Losh-- $FreeBSD$
28088b4f5fSWarner Losh--
29088b4f5fSWarner Losh
30088b4f5fSWarner Losh
31aedd6be5SKyle Evanslocal core = require("core")
32aedd6be5SKyle Evanslocal color = require("color")
33aedd6be5SKyle Evanslocal config = require("config")
34aedd6be5SKyle Evanslocal screen = require("screen")
35aedd6be5SKyle Evanslocal drawer = require("drawer")
36088b4f5fSWarner Losh
37aedd6be5SKyle Evanslocal menu = {}
38c8518398SKyle Evans
39aedd6be5SKyle Evanslocal skip
40aedd6be5SKyle Evanslocal run
41aedd6be5SKyle Evanslocal autoboot
42088b4f5fSWarner Losh
43e15abd1fSKyle Evanslocal OnOff = function(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
53b5746545SKyle Evans-- Module exports
548d415029SKyle Evansmenu.handlers = {
558d415029SKyle Evans	-- Menu handlers take the current menu and selected entry as parameters,
568d415029SKyle Evans	-- and should return a boolean indicating whether execution should
578d415029SKyle Evans	-- continue or not. The return value may be omitted if this entry should
588d415029SKyle Evans	-- have no bearing on whether we continue or not, indicating that we
598d415029SKyle Evans	-- should just continue after execution.
608d415029SKyle Evans	[core.MENU_ENTRY] = function(current_menu, entry)
618d415029SKyle Evans		-- run function
62aedd6be5SKyle Evans		entry.func()
638d415029SKyle Evans	end,
648d415029SKyle Evans	[core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry)
658d415029SKyle Evans		-- carousel (rotating) functionality
66aedd6be5SKyle Evans		local carid = entry.carousel_id
67aedd6be5SKyle Evans		local caridx = config.getCarouselIndex(carid)
68*4f437f9eSKyle Evans		local choices = entry.items
69*4f437f9eSKyle Evans		if type(choices) == "function" then
70*4f437f9eSKyle Evans			choices = choices()
71*4f437f9eSKyle Evans		end
729f71d421SKyle Evans		if #choices > 0 then
73aedd6be5SKyle Evans			caridx = (caridx % #choices) + 1
74aedd6be5SKyle Evans			config.setCarouselIndex(carid, caridx)
75aedd6be5SKyle Evans			entry.func(caridx, choices[caridx], choices)
768d415029SKyle Evans		end
778d415029SKyle Evans	end,
788d415029SKyle Evans	[core.MENU_SUBMENU] = function(current_menu, entry)
798d415029SKyle Evans		-- recurse
809a28f948SKyle Evans		return menu.run(entry.submenu)
818d415029SKyle Evans	end,
828d415029SKyle Evans	[core.MENU_RETURN] = function(current_menu, entry)
838d415029SKyle Evans		-- allow entry to have a function/side effect
849f71d421SKyle Evans		if entry.func ~= nil then
85aedd6be5SKyle Evans			entry.func()
868d415029SKyle Evans		end
87aedd6be5SKyle Evans		return false
888d415029SKyle Evans	end,
89aedd6be5SKyle Evans}
90280e990bSKyle Evans-- loader menu tree is rooted at menu.welcome
91088b4f5fSWarner Losh
92088b4f5fSWarner Loshmenu.boot_options = {
93d8757746SKyle Evans	entries = {
94088b4f5fSWarner Losh		-- return to welcome menu
95088b4f5fSWarner Losh		{
96a7cf0562SKyle Evans			entry_type = core.MENU_RETURN,
97a51f9f0cSKyle Evans			name = "Back to main menu" ..
98a51f9f0cSKyle Evans			    color.highlight(" [Backspace]"),
99088b4f5fSWarner Losh		},
100088b4f5fSWarner Losh		-- load defaults
101088b4f5fSWarner Losh		{
102a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
103a51f9f0cSKyle Evans			name = "Load System " .. color.highlight("D") ..
104a51f9f0cSKyle Evans			    "efaults",
105a51f9f0cSKyle Evans			func = core.setDefaults,
106088b4f5fSWarner Losh			alias = {"d", "D"}
107088b4f5fSWarner Losh		},
108088b4f5fSWarner Losh		{
109a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
110088b4f5fSWarner Losh		},
111088b4f5fSWarner Losh		{
112a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
113a51f9f0cSKyle Evans			name = "Boot Options:",
114088b4f5fSWarner Losh		},
115088b4f5fSWarner Losh		-- acpi
116088b4f5fSWarner Losh		{
117a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
118c1ab36f5SKyle Evans			visible = core.isSystem386,
119088b4f5fSWarner Losh			name = function()
120fd2b19b3SKyle Evans				return OnOff(color.highlight("A") ..
121aedd6be5SKyle Evans				    "CPI       :", core.acpi)
122088b4f5fSWarner Losh			end,
123a51f9f0cSKyle Evans			func = core.setACPI,
124088b4f5fSWarner Losh			alias = {"a", "A"}
125088b4f5fSWarner Losh		},
126088b4f5fSWarner Losh		-- safe mode
127088b4f5fSWarner Losh		{
128a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
129088b4f5fSWarner Losh			name = function()
13057099121SKyle Evans				return OnOff("Safe " .. color.highlight("M") ..
131aedd6be5SKyle Evans				    "ode  :", core.sm)
132088b4f5fSWarner Losh			end,
133a51f9f0cSKyle Evans			func = core.setSafeMode,
134088b4f5fSWarner Losh			alias = {"m", "M"}
135088b4f5fSWarner Losh		},
136088b4f5fSWarner Losh		-- single user
137088b4f5fSWarner Losh		{
138a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
139088b4f5fSWarner Losh			name = function()
140fd2b19b3SKyle Evans				return OnOff(color.highlight("S") ..
141aedd6be5SKyle Evans				    "ingle user:", core.su)
142088b4f5fSWarner Losh			end,
143a51f9f0cSKyle Evans			func = core.setSingleUser,
144088b4f5fSWarner Losh			alias = {"s", "S"}
145088b4f5fSWarner Losh		},
146088b4f5fSWarner Losh		-- verbose boot
147088b4f5fSWarner Losh		{
148a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
149088b4f5fSWarner Losh			name = function()
150fd2b19b3SKyle Evans				return OnOff(color.highlight("V") ..
151aedd6be5SKyle Evans				    "erbose    :", core.verbose)
152088b4f5fSWarner Losh			end,
153a51f9f0cSKyle Evans			func = core.setVerbose,
154088b4f5fSWarner Losh			alias = {"v", "V"}
155088b4f5fSWarner Losh		},
156d8757746SKyle Evans	},
157aedd6be5SKyle Evans}
158088b4f5fSWarner Losh
159088b4f5fSWarner Loshmenu.welcome = {
160303253e5SKyle Evans	entries = function()
161aedd6be5SKyle Evans		local menu_entries = menu.welcome.all_entries
162303253e5SKyle Evans		-- Swap the first two menu items on single user boot
1639f71d421SKyle Evans		if core.isSingleUserBoot() then
1649a0904b0SKyle Evans			-- We'll cache the swapped menu, for performance
1659f71d421SKyle Evans			if menu.welcome.swapped_menu ~= nil then
166aedd6be5SKyle Evans				return menu.welcome.swapped_menu
1679a0904b0SKyle Evans			end
1685c1b5165SKyle Evans			-- Shallow copy the table
169aedd6be5SKyle Evans			menu_entries = core.shallowCopyTable(menu_entries)
1705c1b5165SKyle Evans
1719a0904b0SKyle Evans			-- Swap the first two menu entries
1724b6da14cSKyle Evans			menu_entries[1], menu_entries[2] =
173aedd6be5SKyle Evans			    menu_entries[2], menu_entries[1]
174303253e5SKyle Evans
1759a0904b0SKyle Evans			-- Then set their names to their alternate names
1769a0904b0SKyle Evans			menu_entries[1].name, menu_entries[2].name =
1779a0904b0SKyle Evans			    menu_entries[1].alternate_name,
178aedd6be5SKyle Evans			    menu_entries[2].alternate_name
179aedd6be5SKyle Evans			menu.welcome.swapped_menu = menu_entries
180303253e5SKyle Evans		end
181aedd6be5SKyle Evans		return menu_entries
182303253e5SKyle Evans	end,
183303253e5SKyle Evans	all_entries = {
184088b4f5fSWarner Losh		-- boot multi user
185088b4f5fSWarner Losh		{
186a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
187a51f9f0cSKyle Evans			name = color.highlight("B") .. "oot Multi user " ..
188a51f9f0cSKyle Evans			    color.highlight("[Enter]"),
1895c1b5165SKyle Evans			-- Not a standard menu entry function!
190a51f9f0cSKyle Evans			alternate_name = color.highlight("B") ..
191a51f9f0cSKyle Evans			    "oot Multi user",
192088b4f5fSWarner Losh			func = function()
193aedd6be5SKyle Evans				core.setSingleUser(false)
194aedd6be5SKyle Evans				core.boot()
195088b4f5fSWarner Losh			end,
196b458bf0dSKyle Evans			alias = {"b", "B"}
197088b4f5fSWarner Losh		},
198088b4f5fSWarner Losh		-- boot single user
199088b4f5fSWarner Losh		{
200a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
201a51f9f0cSKyle Evans			name = "Boot " .. color.highlight("S") .. "ingle user",
2025c1b5165SKyle Evans			-- Not a standard menu entry function!
203a51f9f0cSKyle Evans			alternate_name = "Boot " .. color.highlight("S") ..
204a51f9f0cSKyle Evans			    "ingle user " .. color.highlight("[Enter]"),
205088b4f5fSWarner Losh			func = function()
206aedd6be5SKyle Evans				core.setSingleUser(true)
207aedd6be5SKyle Evans				core.boot()
208088b4f5fSWarner Losh			end,
209088b4f5fSWarner Losh			alias = {"s", "S"}
210088b4f5fSWarner Losh		},
211088b4f5fSWarner Losh		-- escape to interpreter
212088b4f5fSWarner Losh		{
213a7cf0562SKyle Evans			entry_type = core.MENU_RETURN,
214a51f9f0cSKyle Evans			name = color.highlight("Esc") .. "ape to loader prompt",
215ef625845SKyle Evans			func = function()
216aedd6be5SKyle Evans				loader.setenv("autoboot_delay", "NO")
217ef625845SKyle Evans			end,
21839006570SKyle Evans			alias = {core.KEYSTR_ESCAPE}
219088b4f5fSWarner Losh		},
220088b4f5fSWarner Losh		-- reboot
221088b4f5fSWarner Losh		{
222a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
223a51f9f0cSKyle Evans			name = color.highlight("R") .. "eboot",
224088b4f5fSWarner Losh			func = function()
225aedd6be5SKyle Evans				loader.perform("reboot")
226088b4f5fSWarner Losh			end,
227088b4f5fSWarner Losh			alias = {"r", "R"}
228088b4f5fSWarner Losh		},
229088b4f5fSWarner Losh		{
230a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
231088b4f5fSWarner Losh		},
232088b4f5fSWarner Losh		{
233a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
234a51f9f0cSKyle Evans			name = "Options:",
235088b4f5fSWarner Losh		},
236088b4f5fSWarner Losh		-- kernel options
237088b4f5fSWarner Losh		{
238a7cf0562SKyle Evans			entry_type = core.MENU_CAROUSEL_ENTRY,
239ada26c4aSKyle Evans			carousel_id = "kernel",
240ada26c4aSKyle Evans			items = core.kernelList,
241ada26c4aSKyle Evans			name = function(idx, choice, all_choices)
2429f71d421SKyle Evans				if #all_choices == 0 then
243aedd6be5SKyle Evans					return "Kernel: "
244088b4f5fSWarner Losh				end
245b1b1f2b8SKyle Evans
246aedd6be5SKyle Evans				local is_default = (idx == 1)
247aedd6be5SKyle Evans				local kernel_name = ""
248aedd6be5SKyle Evans				local name_color
2499f71d421SKyle Evans				if is_default then
250aedd6be5SKyle Evans					name_color = color.escapef(color.GREEN)
251aedd6be5SKyle Evans					kernel_name = "default/"
252bcf48a15SKyle Evans				else
253aedd6be5SKyle Evans					name_color = color.escapef(color.BLUE)
254b1b1f2b8SKyle Evans				end
255fd2b19b3SKyle Evans				kernel_name = kernel_name .. name_color ..
256aedd6be5SKyle Evans				    choice .. color.default()
257fd2b19b3SKyle Evans				return color.highlight("K") .. "ernel: " ..
258fd2b19b3SKyle Evans				    kernel_name .. " (" .. idx .. " of " ..
259aedd6be5SKyle Evans				    #all_choices .. ")"
260088b4f5fSWarner Losh			end,
2615d1e2f83SKyle Evans			func = function(idx, choice, all_choices)
262aedd6be5SKyle Evans				config.selectkernel(choice)
263088b4f5fSWarner Losh			end,
264088b4f5fSWarner Losh			alias = {"k", "K"}
265088b4f5fSWarner Losh		},
266088b4f5fSWarner Losh		-- boot options
267088b4f5fSWarner Losh		{
268a7cf0562SKyle Evans			entry_type = core.MENU_SUBMENU,
269a51f9f0cSKyle Evans			name = "Boot " .. color.highlight("O") .. "ptions",
2709a28f948SKyle Evans			submenu = menu.boot_options,
271088b4f5fSWarner Losh			alias = {"o", "O"}
272d8757746SKyle Evans		},
273d8757746SKyle Evans	},
274aedd6be5SKyle Evans}
275088b4f5fSWarner Losh
27620a81676SKyle Evansmenu.default = menu.welcome
27720a81676SKyle Evans
278088b4f5fSWarner Loshfunction menu.run(m)
279088b4f5fSWarner Losh
2809f71d421SKyle Evans	if menu.skip() then
281aedd6be5SKyle Evans		core.autoboot()
282aedd6be5SKyle Evans		return false
283088b4f5fSWarner Losh	end
284088b4f5fSWarner Losh
2859f71d421SKyle Evans	if m == nil then
28620a81676SKyle Evans		m = menu.default
287088b4f5fSWarner Losh	end
288088b4f5fSWarner Losh
289088b4f5fSWarner Losh	-- redraw screen
290aedd6be5SKyle Evans	screen.clear()
291aedd6be5SKyle Evans	screen.defcursor()
292aedd6be5SKyle Evans	local alias_table = drawer.drawscreen(m)
293088b4f5fSWarner Losh
294aedd6be5SKyle Evans	menu.autoboot()
295088b4f5fSWarner Losh
296aedd6be5SKyle Evans	cont = true
2979f71d421SKyle Evans	while cont do
298aedd6be5SKyle Evans		local key = io.getchar()
299088b4f5fSWarner Losh
300b458bf0dSKyle Evans		-- Special key behaviors
3019f71d421SKyle Evans		if (key == core.KEY_BACKSPACE or key == core.KEY_DELETE) and
30220a81676SKyle Evans		    m ~= menu.default then
303aedd6be5SKyle Evans			break
3049f71d421SKyle Evans		elseif key == core.KEY_ENTER then
305aedd6be5SKyle Evans			core.boot()
306b458bf0dSKyle Evans			-- Should not return
307abc4f7e7SKyle Evans		end
308abc4f7e7SKyle Evans
309abc4f7e7SKyle Evans		key = string.char(key)
310088b4f5fSWarner Losh		-- check to see if key is an alias
311aedd6be5SKyle Evans		local sel_entry = nil
312088b4f5fSWarner Losh		for k, v in pairs(alias_table) do
3139f71d421SKyle Evans			if key == k then
314aedd6be5SKyle Evans				sel_entry = v
315088b4f5fSWarner Losh			end
316088b4f5fSWarner Losh		end
317088b4f5fSWarner Losh
318088b4f5fSWarner Losh		-- if we have an alias do the assigned action:
3199f71d421SKyle Evans		if sel_entry ~= nil then
3208d415029SKyle Evans			-- Get menu handler
321aedd6be5SKyle Evans			local handler = menu.handlers[sel_entry.entry_type]
3229f71d421SKyle Evans			if handler ~= nil then
3238d415029SKyle Evans				-- The handler's return value indicates whether
3248d415029SKyle Evans				-- we need to exit this menu. An omitted return
3258d415029SKyle Evans				-- value means "continue" by default.
326aedd6be5SKyle Evans				cont = handler(m, sel_entry)
3279f71d421SKyle Evans				if cont == nil then
328aedd6be5SKyle Evans					cont = true
329aefcaa7eSKyle Evans				end
330088b4f5fSWarner Losh			end
331088b4f5fSWarner Losh			-- if we got an alias key the screen is out of date:
332aedd6be5SKyle Evans			screen.clear()
333aedd6be5SKyle Evans			screen.defcursor()
334aedd6be5SKyle Evans			alias_table = drawer.drawscreen(m)
335088b4f5fSWarner Losh		end
336088b4f5fSWarner Losh	end
337088b4f5fSWarner Losh
33820a81676SKyle Evans	if m == menu.default then
339aedd6be5SKyle Evans		screen.defcursor()
340aedd6be5SKyle Evans		print("Exiting menu!")
341aedd6be5SKyle Evans		return false
342088b4f5fSWarner Losh	end
343088b4f5fSWarner Losh
344aedd6be5SKyle Evans	return true
345088b4f5fSWarner Loshend
346088b4f5fSWarner Losh
347088b4f5fSWarner Loshfunction menu.skip()
3489f71d421SKyle Evans	if core.isSerialBoot() then
349aedd6be5SKyle Evans		return true
350088b4f5fSWarner Losh	end
351aedd6be5SKyle Evans	local c = string.lower(loader.getenv("console") or "")
3529f71d421SKyle Evans	if c:match("^efi[ ;]") ~= nil or c:match("[ ;]efi[ ;]") ~= nil then
353aedd6be5SKyle Evans		return true
354088b4f5fSWarner Losh	end
355088b4f5fSWarner Losh
356aedd6be5SKyle Evans	c = string.lower(loader.getenv("beastie_disable") or "")
357aedd6be5SKyle Evans	print("beastie_disable", c)
358aedd6be5SKyle Evans	return c == "yes"
359088b4f5fSWarner Loshend
360088b4f5fSWarner Losh
361088b4f5fSWarner Loshfunction menu.autoboot()
36249550489SKyle Evans	if menu.already_autoboot then
363aedd6be5SKyle Evans		return
364088b4f5fSWarner Losh	end
365aedd6be5SKyle Evans	menu.already_autoboot = true
366088b4f5fSWarner Losh
367aedd6be5SKyle Evans	local ab = loader.getenv("autoboot_delay")
3689f71d421SKyle Evans	if ab ~= nil and ab:lower() == "no" then
369aedd6be5SKyle Evans		return
3709f71d421SKyle Evans	elseif tonumber(ab) == -1 then
371aedd6be5SKyle Evans		core.boot()
372088b4f5fSWarner Losh	end
373aedd6be5SKyle Evans	ab = tonumber(ab) or 10
374088b4f5fSWarner Losh
375aedd6be5SKyle Evans	local x = loader.getenv("loader_menu_timeout_x") or 5
376aedd6be5SKyle Evans	local y = loader.getenv("loader_menu_timeout_y") or 22
377088b4f5fSWarner Losh
378aedd6be5SKyle Evans	local endtime = loader.time() + ab
379aedd6be5SKyle Evans	local time
380088b4f5fSWarner Losh
381088b4f5fSWarner Losh	repeat
382aedd6be5SKyle Evans		time = endtime - loader.time()
383aedd6be5SKyle Evans		screen.setcursor(x, y)
38457099121SKyle Evans		print("Autoboot in " .. time ..
38557099121SKyle Evans		    " seconds, hit [Enter] to boot" ..
386aedd6be5SKyle Evans		    " or any other key to stop     ")
387aedd6be5SKyle Evans		screen.defcursor()
3889f71d421SKyle Evans		if io.ischar() then
389aedd6be5SKyle Evans			local ch = io.getchar()
3909f71d421SKyle Evans			if ch == core.KEY_ENTER then
391aedd6be5SKyle Evans				break
392088b4f5fSWarner Losh			else
393088b4f5fSWarner Losh				-- erase autoboot msg
394aedd6be5SKyle Evans				screen.setcursor(0, y)
395088b4f5fSWarner Losh				print("                                        "
396aedd6be5SKyle Evans				    .. "                                        ")
397aedd6be5SKyle Evans				screen.defcursor()
398aedd6be5SKyle Evans				return
399088b4f5fSWarner Losh			end
400088b4f5fSWarner Losh		end
401088b4f5fSWarner Losh
402aedd6be5SKyle Evans		loader.delay(50000)
403aedd6be5SKyle Evans	until time <= 0
404aedd6be5SKyle Evans	core.boot()
405088b4f5fSWarner Losh
406088b4f5fSWarner Loshend
407088b4f5fSWarner Losh
408aedd6be5SKyle Evansreturn menu
409