xref: /freebsd/stand/lua/menu.lua (revision 9a0904b0e07cdfaa21c35fe8f2a9571c518b1352)
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
31088b4f5fSWarner Loshlocal core = require("core");
32088b4f5fSWarner Loshlocal color = require("color");
33088b4f5fSWarner Loshlocal config = require("config");
34088b4f5fSWarner Loshlocal screen = require("screen");
35088b4f5fSWarner Loshlocal drawer = require("drawer");
36088b4f5fSWarner Losh
37c8518398SKyle Evanslocal menu = {};
38c8518398SKyle Evans
39088b4f5fSWarner Loshlocal OnOff;
40088b4f5fSWarner Loshlocal skip;
41088b4f5fSWarner Loshlocal run;
42088b4f5fSWarner Loshlocal autoboot;
43ada26c4aSKyle Evanslocal carousel_choices = {};
44088b4f5fSWarner Losh
45280e990bSKyle Evans-- loader menu tree is rooted at menu.welcome
46088b4f5fSWarner Losh
47088b4f5fSWarner Loshmenu.boot_options = {
48d8757746SKyle Evans	entries = {
49088b4f5fSWarner Losh		-- return to welcome menu
50088b4f5fSWarner Losh		{
51a7cf0562SKyle Evans			entry_type = core.MENU_RETURN,
52088b4f5fSWarner Losh			name = function()
5357099121SKyle Evans				return "Back to main menu" ..
5457099121SKyle Evans				    color.highlight(" [Backspace]");
551666dfc0SKyle Evans			end
56088b4f5fSWarner Losh		},
57088b4f5fSWarner Losh
58088b4f5fSWarner Losh		-- load defaults
59088b4f5fSWarner Losh		{
60a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
61088b4f5fSWarner Losh			name = function()
6257099121SKyle Evans				return "Load System " .. color.highlight("D") ..
6357099121SKyle Evans				    "efaults";
64088b4f5fSWarner Losh			end,
65088b4f5fSWarner Losh			func = function()
6624a1bd54SKyle Evans				core.setDefaults();
67088b4f5fSWarner Losh			end,
68088b4f5fSWarner Losh			alias = {"d", "D"}
69088b4f5fSWarner Losh		},
70088b4f5fSWarner Losh
71088b4f5fSWarner Losh		{
72a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
73088b4f5fSWarner Losh			name = function()
74088b4f5fSWarner Losh				return "";
75088b4f5fSWarner Losh			end
76088b4f5fSWarner Losh		},
77088b4f5fSWarner Losh
78088b4f5fSWarner Losh		{
79a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
80088b4f5fSWarner Losh			name = function()
81088b4f5fSWarner Losh				return "Boot Options:";
82088b4f5fSWarner Losh			end
83088b4f5fSWarner Losh		},
84088b4f5fSWarner Losh
85088b4f5fSWarner Losh		-- acpi
86088b4f5fSWarner Losh		{
87a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
88088b4f5fSWarner Losh			name = function()
89fd2b19b3SKyle Evans				return OnOff(color.highlight("A") ..
90fd2b19b3SKyle Evans				    "CPI       :", core.acpi);
91088b4f5fSWarner Losh			end,
92088b4f5fSWarner Losh			func = function()
93088b4f5fSWarner Losh				core.setACPI();
94088b4f5fSWarner Losh			end,
95088b4f5fSWarner Losh			alias = {"a", "A"}
96088b4f5fSWarner Losh		},
97088b4f5fSWarner Losh		-- safe mode
98088b4f5fSWarner Losh		{
99a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
100088b4f5fSWarner Losh			name = function()
10157099121SKyle Evans				return OnOff("Safe " .. color.highlight("M") ..
10257099121SKyle Evans				    "ode  :", core.sm);
103088b4f5fSWarner Losh			end,
104088b4f5fSWarner Losh			func = function()
105088b4f5fSWarner Losh				core.setSafeMode();
106088b4f5fSWarner Losh			end,
107088b4f5fSWarner Losh			alias = {"m", "M"}
108088b4f5fSWarner Losh		},
109088b4f5fSWarner Losh		-- single user
110088b4f5fSWarner Losh		{
111a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
112088b4f5fSWarner Losh			name = function()
113fd2b19b3SKyle Evans				return OnOff(color.highlight("S") ..
114fd2b19b3SKyle Evans				    "ingle user:", core.su);
115088b4f5fSWarner Losh			end,
116088b4f5fSWarner Losh			func = function()
117088b4f5fSWarner Losh				core.setSingleUser();
118088b4f5fSWarner Losh			end,
119088b4f5fSWarner Losh			alias = {"s", "S"}
120088b4f5fSWarner Losh		},
121088b4f5fSWarner Losh		-- verbose boot
122088b4f5fSWarner Losh		{
123a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
124088b4f5fSWarner Losh			name = function()
125fd2b19b3SKyle Evans				return OnOff(color.highlight("V") ..
126fd2b19b3SKyle Evans				    "erbose    :", core.verbose);
127088b4f5fSWarner Losh			end,
128088b4f5fSWarner Losh			func = function()
129088b4f5fSWarner Losh				core.setVerbose();
130088b4f5fSWarner Losh			end,
131088b4f5fSWarner Losh			alias = {"v", "V"}
132088b4f5fSWarner Losh		},
133d8757746SKyle Evans	},
134088b4f5fSWarner Losh};
135088b4f5fSWarner Losh
136088b4f5fSWarner Loshmenu.welcome = {
137303253e5SKyle Evans	entries = function()
138303253e5SKyle Evans		local menu_entries = menu.welcome.all_entries;
139303253e5SKyle Evans		-- Swap the first two menu items on single user boot
140303253e5SKyle Evans		if (core.isSingleUserBoot()) then
141*9a0904b0SKyle Evans			-- We'll cache the swapped menu, for performance
142*9a0904b0SKyle Evans			if (menu.welcome.swapped_menu ~= nil) then
143*9a0904b0SKyle Evans				return menu.welcome.swapped_menu;
144*9a0904b0SKyle Evans			end
1455c1b5165SKyle Evans			-- Shallow copy the table
1465c1b5165SKyle Evans			menu_entries = core.shallowCopyTable(menu_entries);
1475c1b5165SKyle Evans
148*9a0904b0SKyle Evans			-- Swap the first two menu entries
149*9a0904b0SKyle Evans			menu_entries[1], menu_entries[2] = menu_entries[2],
150*9a0904b0SKyle Evans			    menu_entries[1];
151303253e5SKyle Evans
152*9a0904b0SKyle Evans			-- Then set their names to their alternate names
153*9a0904b0SKyle Evans			menu_entries[1].name, menu_entries[2].name =
154*9a0904b0SKyle Evans			    menu_entries[1].alternate_name,
155*9a0904b0SKyle Evans			    menu_entries[2].alternate_name;
156*9a0904b0SKyle Evans			menu.welcome.swapped_menu = menu_entries;
157303253e5SKyle Evans		end
158303253e5SKyle Evans		return menu_entries;
159303253e5SKyle Evans	end,
160303253e5SKyle Evans	all_entries = {
161088b4f5fSWarner Losh		-- boot multi user
162088b4f5fSWarner Losh		{
163a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
164088b4f5fSWarner Losh			name = function()
165fd2b19b3SKyle Evans				return color.highlight("B") ..
166fd2b19b3SKyle Evans				    "oot Multi user " ..
16757099121SKyle Evans				    color.highlight("[Enter]");
168088b4f5fSWarner Losh			end,
1695c1b5165SKyle Evans			-- Not a standard menu entry function!
1705c1b5165SKyle Evans			alternate_name = function()
1715c1b5165SKyle Evans				return color.highlight("B") ..
1725c1b5165SKyle Evans				    "oot Multi user";
1735c1b5165SKyle Evans			end,
174088b4f5fSWarner Losh			func = function()
175088b4f5fSWarner Losh				core.setSingleUser(false);
176088b4f5fSWarner Losh				core.boot();
177088b4f5fSWarner Losh			end,
178b458bf0dSKyle Evans			alias = {"b", "B"}
179088b4f5fSWarner Losh		},
180088b4f5fSWarner Losh
181088b4f5fSWarner Losh		-- boot single user
182088b4f5fSWarner Losh		{
183a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
184088b4f5fSWarner Losh			name = function()
185fd2b19b3SKyle Evans				return "Boot " .. color.highlight("S") ..
186fd2b19b3SKyle Evans				    "ingle user";
187088b4f5fSWarner Losh			end,
1885c1b5165SKyle Evans			-- Not a standard menu entry function!
1895c1b5165SKyle Evans			alternate_name = function()
1905c1b5165SKyle Evans				return "Boot " .. color.highlight("S") ..
1915c1b5165SKyle Evans				    "ingle user " .. color.highlight("[Enter]");
1925c1b5165SKyle Evans			end,
193088b4f5fSWarner Losh			func = function()
194088b4f5fSWarner Losh				core.setSingleUser(true);
195088b4f5fSWarner Losh				core.boot();
196088b4f5fSWarner Losh			end,
197088b4f5fSWarner Losh			alias = {"s", "S"}
198088b4f5fSWarner Losh		},
199088b4f5fSWarner Losh
200088b4f5fSWarner Losh		-- escape to interpreter
201088b4f5fSWarner Losh		{
202a7cf0562SKyle Evans			entry_type = core.MENU_RETURN,
203088b4f5fSWarner Losh			name = function()
204fd2b19b3SKyle Evans				return color.highlight("Esc") ..
205fd2b19b3SKyle Evans				    "ape to loader prompt";
206088b4f5fSWarner Losh			end,
207ef625845SKyle Evans			func = function()
20824a1bd54SKyle Evans				loader.setenv("autoboot_delay", "NO");
209ef625845SKyle Evans			end,
21039006570SKyle Evans			alias = {core.KEYSTR_ESCAPE}
211088b4f5fSWarner Losh		},
212088b4f5fSWarner Losh
213088b4f5fSWarner Losh		-- reboot
214088b4f5fSWarner Losh		{
215a7cf0562SKyle Evans			entry_type = core.MENU_ENTRY,
216088b4f5fSWarner Losh			name = function()
217088b4f5fSWarner Losh				return color.highlight("R") .. "eboot";
218088b4f5fSWarner Losh			end,
219088b4f5fSWarner Losh			func = function()
220088b4f5fSWarner Losh				loader.perform("reboot");
221088b4f5fSWarner Losh			end,
222088b4f5fSWarner Losh			alias = {"r", "R"}
223088b4f5fSWarner Losh		},
224088b4f5fSWarner Losh
225088b4f5fSWarner Losh
226088b4f5fSWarner Losh		{
227a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
228088b4f5fSWarner Losh			name = function()
229088b4f5fSWarner Losh				return "";
230088b4f5fSWarner Losh			end
231088b4f5fSWarner Losh		},
232088b4f5fSWarner Losh
233088b4f5fSWarner Losh		{
234a7cf0562SKyle Evans			entry_type = core.MENU_SEPARATOR,
235088b4f5fSWarner Losh			name = function()
236088b4f5fSWarner Losh				return "Options:";
237088b4f5fSWarner Losh			end
238088b4f5fSWarner Losh		},
239088b4f5fSWarner Losh
240088b4f5fSWarner Losh		-- kernel options
241088b4f5fSWarner Losh		{
242a7cf0562SKyle Evans			entry_type = core.MENU_CAROUSEL_ENTRY,
243ada26c4aSKyle Evans			carousel_id = "kernel",
244ada26c4aSKyle Evans			items = core.kernelList,
245ada26c4aSKyle Evans			name = function(idx, choice, all_choices)
24624a1bd54SKyle Evans				if (#all_choices == 0) then
247b1b1f2b8SKyle Evans					return "Kernel: ";
248088b4f5fSWarner Losh				end
249b1b1f2b8SKyle Evans
250bcf48a15SKyle Evans				local is_default = (idx == 1);
251bcf48a15SKyle Evans				local kernel_name = "";
252bcf48a15SKyle Evans				local name_color;
25324a1bd54SKyle Evans				if (is_default) then
254bcf48a15SKyle Evans					name_color = color.escapef(color.GREEN);
255bcf48a15SKyle Evans					kernel_name = "default/";
256bcf48a15SKyle Evans				else
257bcf48a15SKyle Evans					name_color = color.escapef(color.BLUE);
258b1b1f2b8SKyle Evans				end
259fd2b19b3SKyle Evans				kernel_name = kernel_name .. name_color ..
260fd2b19b3SKyle Evans				    choice .. color.default();
261fd2b19b3SKyle Evans				return color.highlight("K") .. "ernel: " ..
262fd2b19b3SKyle Evans				    kernel_name .. " (" .. idx .. " of " ..
263fd2b19b3SKyle Evans				    #all_choices .. ")";
264088b4f5fSWarner Losh			end,
2655d1e2f83SKyle Evans			func = function(idx, choice, all_choices)
266fa4a2394SKyle Evans				config.selectkernel(choice);
267088b4f5fSWarner Losh			end,
268088b4f5fSWarner Losh			alias = {"k", "K"}
269088b4f5fSWarner Losh		},
270088b4f5fSWarner Losh
271088b4f5fSWarner Losh		-- boot options
272088b4f5fSWarner Losh		{
273a7cf0562SKyle Evans			entry_type = core.MENU_SUBMENU,
274088b4f5fSWarner Losh			name = function()
275fd2b19b3SKyle Evans				return "Boot " .. color.highlight("O") ..
276fd2b19b3SKyle Evans				    "ptions";
277088b4f5fSWarner Losh			end,
278088b4f5fSWarner Losh			submenu = function()
279088b4f5fSWarner Losh				return menu.boot_options;
280088b4f5fSWarner Losh			end,
281088b4f5fSWarner Losh			alias = {"o", "O"}
282d8757746SKyle Evans		},
283d8757746SKyle Evans	},
284088b4f5fSWarner Losh};
285088b4f5fSWarner Losh
286ada26c4aSKyle Evans-- The first item in every carousel is always the default item.
287ada26c4aSKyle Evansfunction menu.getCarouselIndex(id)
288ada26c4aSKyle Evans	local val = carousel_choices[id];
289ada26c4aSKyle Evans	if (val == nil) then
290ada26c4aSKyle Evans		return 1;
291ada26c4aSKyle Evans	end
292ada26c4aSKyle Evans	return val;
293ada26c4aSKyle Evansend
294ada26c4aSKyle Evans
295ada26c4aSKyle Evansfunction menu.setCarouselIndex(id, idx)
296ada26c4aSKyle Evans	carousel_choices[id] = idx;
297ada26c4aSKyle Evansend
298ada26c4aSKyle Evans
299088b4f5fSWarner Loshfunction menu.run(m)
300088b4f5fSWarner Losh
301088b4f5fSWarner Losh	if (menu.skip()) then
302088b4f5fSWarner Losh		core.autoboot();
303088b4f5fSWarner Losh		return false;
304088b4f5fSWarner Losh	end
305088b4f5fSWarner Losh
306088b4f5fSWarner Losh	if (m == nil) then
307088b4f5fSWarner Losh		m = menu.welcome;
308088b4f5fSWarner Losh	end
309088b4f5fSWarner Losh
310088b4f5fSWarner Losh	-- redraw screen
311088b4f5fSWarner Losh	screen.clear();
312088b4f5fSWarner Losh	screen.defcursor();
313088b4f5fSWarner Losh	local alias_table = drawer.drawscreen(m);
314088b4f5fSWarner Losh
3153a0a07d0SKyle Evans	menu.autoboot();
316088b4f5fSWarner Losh
317088b4f5fSWarner Losh	cont = true;
31824a1bd54SKyle Evans	while (cont) do
319abc4f7e7SKyle Evans		local key = io.getchar();
320088b4f5fSWarner Losh
321b458bf0dSKyle Evans		-- Special key behaviors
3221504bce3SKyle Evans		if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and
3231504bce3SKyle Evans		    (m ~= menu.welcome) then
3241f5696c7SKyle Evans			break;
325fe672a15SKyle Evans		elseif (key == core.KEY_ENTER) then
326b458bf0dSKyle Evans			core.boot();
327b458bf0dSKyle Evans			-- Should not return
328abc4f7e7SKyle Evans		end
329abc4f7e7SKyle Evans
330abc4f7e7SKyle Evans		key = string.char(key)
331088b4f5fSWarner Losh		-- check to see if key is an alias
332088b4f5fSWarner Losh		local sel_entry = nil;
333088b4f5fSWarner Losh		for k, v in pairs(alias_table) do
334088b4f5fSWarner Losh			if (key == k) then
335088b4f5fSWarner Losh				sel_entry = v;
336088b4f5fSWarner Losh			end
337088b4f5fSWarner Losh		end
338088b4f5fSWarner Losh
339088b4f5fSWarner Losh		-- if we have an alias do the assigned action:
340088b4f5fSWarner Losh		if (sel_entry ~= nil) then
341a7cf0562SKyle Evans			if (sel_entry.entry_type == core.MENU_ENTRY) then
342088b4f5fSWarner Losh				-- run function
343088b4f5fSWarner Losh				sel_entry.func();
344a7cf0562SKyle Evans			elseif (sel_entry.entry_type == core.MENU_CAROUSEL_ENTRY) then
345ada26c4aSKyle Evans				-- carousel (rotating) functionality
346ada26c4aSKyle Evans				local carid = sel_entry.carousel_id;
347ada26c4aSKyle Evans				local caridx = menu.getCarouselIndex(carid);
348ada26c4aSKyle Evans				local choices = sel_entry.items();
349ada26c4aSKyle Evans
350aefcaa7eSKyle Evans				if (#choices > 0) then
351ada26c4aSKyle Evans					caridx = (caridx % #choices) + 1;
352ada26c4aSKyle Evans					menu.setCarouselIndex(carid, caridx);
3535d1e2f83SKyle Evans					sel_entry.func(caridx, choices[caridx],
35484f82e46SKyle Evans					    choices);
355aefcaa7eSKyle Evans				end
356a7cf0562SKyle Evans			elseif (sel_entry.entry_type == core.MENU_SUBMENU) then
357088b4f5fSWarner Losh				-- recurse
358088b4f5fSWarner Losh				cont = menu.run(sel_entry.submenu());
359a7cf0562SKyle Evans			elseif (sel_entry.entry_type == core.MENU_RETURN) then
360ef625845SKyle Evans				-- allow entry to have a function/side effect
361ef625845SKyle Evans				if (sel_entry.func ~= nil) then
362ef625845SKyle Evans					sel_entry.func();
363ef625845SKyle Evans				end
364088b4f5fSWarner Losh				-- break recurse
365088b4f5fSWarner Losh				cont = false;
366088b4f5fSWarner Losh			end
367088b4f5fSWarner Losh			-- if we got an alias key the screen is out of date:
368088b4f5fSWarner Losh			screen.clear();
369088b4f5fSWarner Losh			screen.defcursor();
370088b4f5fSWarner Losh			alias_table = drawer.drawscreen(m);
371088b4f5fSWarner Losh		end
372088b4f5fSWarner Losh	end
373088b4f5fSWarner Losh
374088b4f5fSWarner Losh	if (m == menu.welcome) then
375088b4f5fSWarner Losh		screen.defcursor();
376088b4f5fSWarner Losh		print("Exiting menu!");
377fa4a2394SKyle Evans		config.loadelf();
378088b4f5fSWarner Losh		return false;
379088b4f5fSWarner Losh	end
380088b4f5fSWarner Losh
381088b4f5fSWarner Losh	return true;
382088b4f5fSWarner Loshend
383088b4f5fSWarner Losh
384088b4f5fSWarner Loshfunction menu.skip()
385b140d14bSKyle Evans	if (core.isSerialBoot()) then
386088b4f5fSWarner Losh		return true;
387088b4f5fSWarner Losh	end
388088b4f5fSWarner Losh	local c = string.lower(loader.getenv("console") or "");
38924a1bd54SKyle Evans	if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then
390088b4f5fSWarner Losh		return true;
391088b4f5fSWarner Losh	end
392088b4f5fSWarner Losh
393088b4f5fSWarner Losh	c = string.lower(loader.getenv("beastie_disable") or "");
394088b4f5fSWarner Losh	print("beastie_disable", c);
395088b4f5fSWarner Losh	return c == "yes";
396088b4f5fSWarner Loshend
397088b4f5fSWarner Losh
398088b4f5fSWarner Loshfunction menu.autoboot()
39924a1bd54SKyle Evans	if (menu.already_autoboot == true) then
400088b4f5fSWarner Losh		return;
401088b4f5fSWarner Losh	end
402088b4f5fSWarner Losh	menu.already_autoboot = true;
403088b4f5fSWarner Losh
404088b4f5fSWarner Losh	local ab = loader.getenv("autoboot_delay");
405702b460dSKyle Evans	if (ab ~= nil) and (ab:lower() == "no") then
406702b460dSKyle Evans		return;
407702b460dSKyle Evans	elseif (tonumber(ab) == -1) then
408088b4f5fSWarner Losh		core.boot();
409088b4f5fSWarner Losh	end
410088b4f5fSWarner Losh	ab = tonumber(ab) or 10;
411088b4f5fSWarner Losh
412088b4f5fSWarner Losh	local x = loader.getenv("loader_menu_timeout_x") or 5;
413088b4f5fSWarner Losh	local y = loader.getenv("loader_menu_timeout_y") or 22;
414088b4f5fSWarner Losh
415088b4f5fSWarner Losh	local endtime = loader.time() + ab;
416088b4f5fSWarner Losh	local time;
417088b4f5fSWarner Losh
418088b4f5fSWarner Losh	repeat
419088b4f5fSWarner Losh		time = endtime - loader.time();
420088b4f5fSWarner Losh		screen.setcursor(x, y);
42157099121SKyle Evans		print("Autoboot in " .. time ..
42257099121SKyle Evans		    " seconds, hit [Enter] to boot" ..
42357099121SKyle Evans		    " or any other key to stop     ");
424088b4f5fSWarner Losh		screen.defcursor();
42524a1bd54SKyle Evans		if (io.ischar()) then
426088b4f5fSWarner Losh			local ch = io.getchar();
42724a1bd54SKyle Evans			if (ch == core.KEY_ENTER) then
428088b4f5fSWarner Losh				break;
429088b4f5fSWarner Losh			else
430088b4f5fSWarner Losh				-- erase autoboot msg
431088b4f5fSWarner Losh				screen.setcursor(0, y);
432088b4f5fSWarner Losh				print("                                        "
433088b4f5fSWarner Losh				    .. "                                        ");
434088b4f5fSWarner Losh				screen.defcursor();
435088b4f5fSWarner Losh				return;
436088b4f5fSWarner Losh			end
437088b4f5fSWarner Losh		end
438088b4f5fSWarner Losh
439088b4f5fSWarner Losh		loader.delay(50000);
4401f5696c7SKyle Evans	until time <= 0;
441088b4f5fSWarner Losh	core.boot();
442088b4f5fSWarner Losh
443088b4f5fSWarner Loshend
444088b4f5fSWarner Losh
445088b4f5fSWarner Loshfunction OnOff(str, b)
446088b4f5fSWarner Losh	if (b) then
44757099121SKyle Evans		return str .. color.escapef(color.GREEN) .. "On" ..
44857099121SKyle Evans		    color.escapef(color.WHITE);
449088b4f5fSWarner Losh	else
45057099121SKyle Evans		return str .. color.escapef(color.RED) .. "off" ..
45157099121SKyle Evans		    color.escapef(color.WHITE);
452088b4f5fSWarner Losh	end
453088b4f5fSWarner Loshend
454088b4f5fSWarner Losh
45524a1bd54SKyle Evansreturn menu;
456