xref: /freebsd/stand/lua/menu.lua (revision b458bf0da189587ec98a715fcb30da3317263cde)
1088b4f5fSWarner Losh--
2088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3088b4f5fSWarner Losh-- All rights reserved.
4088b4f5fSWarner Losh--
5088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without
6088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions
7088b4f5fSWarner Losh-- are met:
8088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright
9088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer.
10088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright
11088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer in the
12088b4f5fSWarner Losh--    documentation and/or other materials provided with the distribution.
13088b4f5fSWarner Losh--
14088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17088b4f5fSWarner Losh-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24088b4f5fSWarner Losh-- SUCH DAMAGE.
25088b4f5fSWarner Losh--
26088b4f5fSWarner Losh-- $FreeBSD$
27088b4f5fSWarner Losh--
28088b4f5fSWarner Losh
29088b4f5fSWarner Losh
30088b4f5fSWarner Loshlocal menu = {};
31088b4f5fSWarner Losh
32088b4f5fSWarner Loshlocal core = require("core");
33088b4f5fSWarner Loshlocal color = require("color");
34088b4f5fSWarner Loshlocal config = require("config");
35088b4f5fSWarner Loshlocal screen = require("screen");
36088b4f5fSWarner Loshlocal drawer = require("drawer");
37088b4f5fSWarner Losh
38088b4f5fSWarner Loshlocal OnOff;
39088b4f5fSWarner Loshlocal skip;
40088b4f5fSWarner Loshlocal run;
41088b4f5fSWarner Loshlocal autoboot;
42088b4f5fSWarner Losh
43088b4f5fSWarner Losh--loader menu tree:
44088b4f5fSWarner Losh--rooted at menu.welcome
45088b4f5fSWarner Losh--submenu declarations:
46088b4f5fSWarner Loshlocal kernel_options;
47088b4f5fSWarner Loshlocal boot_options;
48088b4f5fSWarner Loshlocal welcome;
49088b4f5fSWarner Losh
50088b4f5fSWarner Loshmenu.kernel_options = {
51088b4f5fSWarner Losh	-- this table is dynamically appended to when accessed
52088b4f5fSWarner Losh	-- return to welcome menu
53088b4f5fSWarner Losh	{
54088b4f5fSWarner Losh		entry_type = "return",
55088b4f5fSWarner Losh		name = function()
56088b4f5fSWarner Losh			return "Back to main menu"..color.highlight(" [Backspace]");
57088b4f5fSWarner Losh		end,
58088b4f5fSWarner Losh		alias = {"\08"}
59088b4f5fSWarner Losh	}
60088b4f5fSWarner Losh};
61088b4f5fSWarner Losh
62088b4f5fSWarner Loshmenu.boot_options = {
63088b4f5fSWarner Losh	-- return to welcome menu
64088b4f5fSWarner Losh	{
65088b4f5fSWarner Losh		entry_type = "return",
66088b4f5fSWarner Losh		name = function()
67088b4f5fSWarner Losh			return "Back to main menu"..color.highlight(" [Backspace]");
68088b4f5fSWarner Losh		end,
69088b4f5fSWarner Losh		alias = {"\08"}
70088b4f5fSWarner Losh	},
71088b4f5fSWarner Losh
72088b4f5fSWarner Losh	-- load defaults
73088b4f5fSWarner Losh	{
74088b4f5fSWarner Losh		entry_type = "entry",
75088b4f5fSWarner Losh		name = function()
76088b4f5fSWarner Losh			return "Load System "..color.highlight("D").."efaults";
77088b4f5fSWarner Losh		end,
78088b4f5fSWarner Losh		func = function()
79088b4f5fSWarner Losh			core.setDefaults()
80088b4f5fSWarner Losh		end,
81088b4f5fSWarner Losh		alias = {"d", "D"}
82088b4f5fSWarner Losh	},
83088b4f5fSWarner Losh
84088b4f5fSWarner Losh	{
85088b4f5fSWarner Losh		entry_type = "separator",
86088b4f5fSWarner Losh		name = function()
87088b4f5fSWarner Losh			return "";
88088b4f5fSWarner Losh		end
89088b4f5fSWarner Losh	},
90088b4f5fSWarner Losh
91088b4f5fSWarner Losh	{
92088b4f5fSWarner Losh		entry_type = "separator",
93088b4f5fSWarner Losh		name = function()
94088b4f5fSWarner Losh			return "Boot Options:";
95088b4f5fSWarner Losh		end
96088b4f5fSWarner Losh	},
97088b4f5fSWarner Losh
98088b4f5fSWarner Losh	-- acpi
99088b4f5fSWarner Losh	{
100088b4f5fSWarner Losh		entry_type = "entry",
101088b4f5fSWarner Losh		name = function()
102088b4f5fSWarner Losh			return OnOff(color.highlight("A").."CPI       :", core.acpi);
103088b4f5fSWarner Losh		end,
104088b4f5fSWarner Losh		func = function()
105088b4f5fSWarner Losh			core.setACPI();
106088b4f5fSWarner Losh		end,
107088b4f5fSWarner Losh		alias = {"a", "A"}
108088b4f5fSWarner Losh	},
109088b4f5fSWarner Losh	-- safe mode
110088b4f5fSWarner Losh	{
111088b4f5fSWarner Losh		entry_type = "entry",
112088b4f5fSWarner Losh		name = function()
113088b4f5fSWarner Losh			return OnOff("Safe "..color.highlight("M").."ode  :", core.sm);
114088b4f5fSWarner Losh		end,
115088b4f5fSWarner Losh		func = function()
116088b4f5fSWarner Losh			core.setSafeMode();
117088b4f5fSWarner Losh		end,
118088b4f5fSWarner Losh		alias = {"m", "M"}
119088b4f5fSWarner Losh	},
120088b4f5fSWarner Losh	-- single user
121088b4f5fSWarner Losh	{
122088b4f5fSWarner Losh		entry_type = "entry",
123088b4f5fSWarner Losh		name = function()
124088b4f5fSWarner Losh			return OnOff(color.highlight("S").."ingle user:", core.su);
125088b4f5fSWarner Losh		end,
126088b4f5fSWarner Losh		func = function()
127088b4f5fSWarner Losh			core.setSingleUser();
128088b4f5fSWarner Losh		end,
129088b4f5fSWarner Losh		alias = {"s", "S"}
130088b4f5fSWarner Losh	},
131088b4f5fSWarner Losh	-- verbose boot
132088b4f5fSWarner Losh	{
133088b4f5fSWarner Losh		entry_type = "entry",
134088b4f5fSWarner Losh		name = function()
135088b4f5fSWarner Losh			return OnOff(color.highlight("V").."erbose    :", core.verbose);
136088b4f5fSWarner Losh		end,
137088b4f5fSWarner Losh		func = function()
138088b4f5fSWarner Losh			core.setVerbose();
139088b4f5fSWarner Losh		end,
140088b4f5fSWarner Losh		alias = {"v", "V"}
141088b4f5fSWarner Losh	},
142088b4f5fSWarner Losh};
143088b4f5fSWarner Losh
144088b4f5fSWarner Loshmenu.welcome = {
145088b4f5fSWarner Losh	-- boot multi user
146088b4f5fSWarner Losh	{
147088b4f5fSWarner Losh		entry_type = "entry",
148088b4f5fSWarner Losh		name = function()
149088b4f5fSWarner Losh			return color.highlight("B").."oot Multi user "..color.highlight("[Enter]");
150088b4f5fSWarner Losh		end,
151088b4f5fSWarner Losh		func = function()
152088b4f5fSWarner Losh			core.setSingleUser(false);
153088b4f5fSWarner Losh			core.boot();
154088b4f5fSWarner Losh		end,
155*b458bf0dSKyle Evans		alias = {"b", "B"}
156088b4f5fSWarner Losh	},
157088b4f5fSWarner Losh
158088b4f5fSWarner Losh	-- boot single user
159088b4f5fSWarner Losh	{
160088b4f5fSWarner Losh		entry_type = "entry",
161088b4f5fSWarner Losh		name = function()
162088b4f5fSWarner Losh			return "Boot "..color.highlight("S").."ingle user";
163088b4f5fSWarner Losh		end,
164088b4f5fSWarner Losh		func = function()
165088b4f5fSWarner Losh			core.setSingleUser(true);
166088b4f5fSWarner Losh			core.boot();
167088b4f5fSWarner Losh		end,
168088b4f5fSWarner Losh		alias = {"s", "S"}
169088b4f5fSWarner Losh	},
170088b4f5fSWarner Losh
171088b4f5fSWarner Losh	-- escape to interpreter
172088b4f5fSWarner Losh	{
173088b4f5fSWarner Losh		entry_type = "return",
174088b4f5fSWarner Losh		name = function()
175088b4f5fSWarner Losh			return color.highlight("Esc").."ape to lua interpreter";
176088b4f5fSWarner Losh		end,
177088b4f5fSWarner Losh		alias = {"\027"}
178088b4f5fSWarner Losh	},
179088b4f5fSWarner Losh
180088b4f5fSWarner Losh	-- reboot
181088b4f5fSWarner Losh	{
182088b4f5fSWarner Losh		entry_type = "entry",
183088b4f5fSWarner Losh		name = function()
184088b4f5fSWarner Losh			return color.highlight("R").."eboot";
185088b4f5fSWarner Losh		end,
186088b4f5fSWarner Losh		func = function()
187088b4f5fSWarner Losh			loader.perform("reboot");
188088b4f5fSWarner Losh		end,
189088b4f5fSWarner Losh		alias = {"r", "R"}
190088b4f5fSWarner Losh	},
191088b4f5fSWarner Losh
192088b4f5fSWarner Losh
193088b4f5fSWarner Losh	{
194088b4f5fSWarner Losh		entry_type = "separator",
195088b4f5fSWarner Losh		name = function()
196088b4f5fSWarner Losh			return "";
197088b4f5fSWarner Losh		end
198088b4f5fSWarner Losh	},
199088b4f5fSWarner Losh
200088b4f5fSWarner Losh	{
201088b4f5fSWarner Losh		entry_type = "separator",
202088b4f5fSWarner Losh		name = function()
203088b4f5fSWarner Losh			return "Options:";
204088b4f5fSWarner Losh		end
205088b4f5fSWarner Losh	},
206088b4f5fSWarner Losh
207088b4f5fSWarner Losh	-- kernel options
208088b4f5fSWarner Losh	{
209088b4f5fSWarner Losh		entry_type = "submenu",
210088b4f5fSWarner Losh		name = function()
211088b4f5fSWarner Losh			local kernels = core.kernelList();
212088b4f5fSWarner Losh			if #kernels == 0 then
213088b4f5fSWarner Losh				return "Kernels (not available)";
214088b4f5fSWarner Losh			end
215088b4f5fSWarner Losh			return color.highlight("K").."ernels";
216088b4f5fSWarner Losh		end,
217088b4f5fSWarner Losh		submenu = function()
218088b4f5fSWarner Losh
219088b4f5fSWarner Losh			-- dynamically build the kernel menu:
220088b4f5fSWarner Losh			local kernels = core.kernelList();
221088b4f5fSWarner Losh			for k, v in ipairs(kernels) do
222088b4f5fSWarner Losh				menu.kernel_options[#menu.kernel_options + 1] = {
223088b4f5fSWarner Losh					entry_type = "entry",
224088b4f5fSWarner Losh					name = function()
225088b4f5fSWarner Losh						return v;
226088b4f5fSWarner Losh					end,
227088b4f5fSWarner Losh					func = function()
228088b4f5fSWarner Losh						config.reload(v);
229088b4f5fSWarner Losh					end,
230088b4f5fSWarner Losh					alias = {} -- automatically enumerated
231088b4f5fSWarner Losh				}
232088b4f5fSWarner Losh			end
233088b4f5fSWarner Losh
234088b4f5fSWarner Losh			return menu.kernel_options;
235088b4f5fSWarner Losh		end,
236088b4f5fSWarner Losh		alias = {"k", "K"}
237088b4f5fSWarner Losh	},
238088b4f5fSWarner Losh
239088b4f5fSWarner Losh	-- boot options
240088b4f5fSWarner Losh	{
241088b4f5fSWarner Losh		entry_type = "submenu",
242088b4f5fSWarner Losh		name = function()
243088b4f5fSWarner Losh			return "Boot "..color.highlight("O").."ptions";
244088b4f5fSWarner Losh		end,
245088b4f5fSWarner Losh		submenu = function()
246088b4f5fSWarner Losh			return menu.boot_options;
247088b4f5fSWarner Losh		end,
248088b4f5fSWarner Losh		alias = {"o", "O"}
249088b4f5fSWarner Losh	}
250088b4f5fSWarner Losh
251088b4f5fSWarner Losh};
252088b4f5fSWarner Losh
253088b4f5fSWarner Loshfunction menu.run(m)
254088b4f5fSWarner Losh
255088b4f5fSWarner Losh	if (menu.skip()) then
256088b4f5fSWarner Losh		core.autoboot();
257088b4f5fSWarner Losh		return false;
258088b4f5fSWarner Losh	end
259088b4f5fSWarner Losh
260088b4f5fSWarner Losh	if (m == nil) then
261088b4f5fSWarner Losh		m = menu.welcome;
262088b4f5fSWarner Losh	end
263088b4f5fSWarner Losh
264088b4f5fSWarner Losh	-- redraw screen
265088b4f5fSWarner Losh	screen.clear();
266088b4f5fSWarner Losh	screen.defcursor();
267088b4f5fSWarner Losh	local alias_table = drawer.drawscreen(m);
268088b4f5fSWarner Losh
269088b4f5fSWarner Losh--	menu.autoboot();
270088b4f5fSWarner Losh
271088b4f5fSWarner Losh	cont = true;
272088b4f5fSWarner Losh	while cont do
273abc4f7e7SKyle Evans		local key = io.getchar();
274088b4f5fSWarner Losh
275*b458bf0dSKyle Evans		-- Special key behaviors
276abc4f7e7SKyle Evans		if (key == 127) and (m ~= menu.welcome) then
277abc4f7e7SKyle Evans			break
278*b458bf0dSKyle Evans		elseif (key == 13) then
279*b458bf0dSKyle Evans			core.boot();
280*b458bf0dSKyle Evans			-- Should not return
281abc4f7e7SKyle Evans		end
282abc4f7e7SKyle Evans
283abc4f7e7SKyle Evans		key = string.char(key)
284088b4f5fSWarner Losh		-- check to see if key is an alias
285088b4f5fSWarner Losh		local sel_entry = nil;
286088b4f5fSWarner Losh		for k, v in pairs(alias_table) do
287088b4f5fSWarner Losh			if (key == k) then
288088b4f5fSWarner Losh				sel_entry = v;
289088b4f5fSWarner Losh			end
290088b4f5fSWarner Losh		end
291088b4f5fSWarner Losh
292088b4f5fSWarner Losh		-- if we have an alias do the assigned action:
293088b4f5fSWarner Losh		if(sel_entry ~= nil) then
294088b4f5fSWarner Losh			if (sel_entry.entry_type == "entry") then
295088b4f5fSWarner Losh				-- run function
296088b4f5fSWarner Losh				sel_entry.func();
297088b4f5fSWarner Losh			elseif (sel_entry.entry_type == "submenu") then
298088b4f5fSWarner Losh				-- recurse
299088b4f5fSWarner Losh				cont = menu.run(sel_entry.submenu());
300088b4f5fSWarner Losh			elseif (sel_entry.entry_type == "return") then
301088b4f5fSWarner Losh				-- break recurse
302088b4f5fSWarner Losh				cont = false;
303088b4f5fSWarner Losh			end
304088b4f5fSWarner Losh			-- if we got an alias key the screen is out of date:
305088b4f5fSWarner Losh			screen.clear();
306088b4f5fSWarner Losh			screen.defcursor();
307088b4f5fSWarner Losh			alias_table = drawer.drawscreen(m);
308088b4f5fSWarner Losh		end
309088b4f5fSWarner Losh	end
310088b4f5fSWarner Losh
311088b4f5fSWarner Losh	if (m == menu.welcome) then
312088b4f5fSWarner Losh		screen.defcursor();
313088b4f5fSWarner Losh		print("Exiting menu!");
314088b4f5fSWarner Losh		return false;
315088b4f5fSWarner Losh	end
316088b4f5fSWarner Losh
317088b4f5fSWarner Losh	return true;
318088b4f5fSWarner Loshend
319088b4f5fSWarner Losh
320088b4f5fSWarner Loshfunction menu.skip()
321088b4f5fSWarner Losh	if core.bootserial() then
322088b4f5fSWarner Losh		return true;
323088b4f5fSWarner Losh	end
324088b4f5fSWarner Losh	local c = string.lower(loader.getenv("console") or "");
325088b4f5fSWarner Losh	if (c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil then
326088b4f5fSWarner Losh		return true;
327088b4f5fSWarner Losh	end
328088b4f5fSWarner Losh
329088b4f5fSWarner Losh	c = string.lower(loader.getenv("beastie_disable") or "");
330088b4f5fSWarner Losh	print("beastie_disable", c);
331088b4f5fSWarner Losh	return c == "yes";
332088b4f5fSWarner Loshend
333088b4f5fSWarner Losh
334088b4f5fSWarner Loshfunction menu.autoboot()
335088b4f5fSWarner Losh	if menu.already_autoboot == true then
336088b4f5fSWarner Losh		return;
337088b4f5fSWarner Losh	end
338088b4f5fSWarner Losh	menu.already_autoboot = true;
339088b4f5fSWarner Losh
340088b4f5fSWarner Losh	local ab = loader.getenv("autoboot_delay");
341088b4f5fSWarner Losh	if ab == "NO" or ab == "no" then
342088b4f5fSWarner Losh		core.boot();
343088b4f5fSWarner Losh	end
344088b4f5fSWarner Losh	ab = tonumber(ab) or 10;
345088b4f5fSWarner Losh
346088b4f5fSWarner Losh	local x = loader.getenv("loader_menu_timeout_x") or 5;
347088b4f5fSWarner Losh	local y = loader.getenv("loader_menu_timeout_y") or 22;
348088b4f5fSWarner Losh
349088b4f5fSWarner Losh	local endtime = loader.time() + ab;
350088b4f5fSWarner Losh	local time;
351088b4f5fSWarner Losh
352088b4f5fSWarner Losh	repeat
353088b4f5fSWarner Losh		time = endtime - loader.time();
354088b4f5fSWarner Losh		screen.setcursor(x, y);
355088b4f5fSWarner Losh		print("Autoboot in "..time.." seconds, hit [Enter] to boot"
356088b4f5fSWarner Losh			      .." or any other key to stop     ");
357088b4f5fSWarner Losh		screen.defcursor();
358088b4f5fSWarner Losh		if io.ischar() then
359088b4f5fSWarner Losh			local ch = io.getchar();
360088b4f5fSWarner Losh			if ch == 13 then
361088b4f5fSWarner Losh				break;
362088b4f5fSWarner Losh			else
363088b4f5fSWarner Losh				-- prevent autoboot when escaping to interpreter
364088b4f5fSWarner Losh				loader.setenv("autoboot_delay", "NO");
365088b4f5fSWarner Losh				-- erase autoboot msg
366088b4f5fSWarner Losh				screen.setcursor(0, y);
367088b4f5fSWarner Losh				print("                                        "
368088b4f5fSWarner Losh					      .."                                        ");
369088b4f5fSWarner Losh				screen.defcursor();
370088b4f5fSWarner Losh				return;
371088b4f5fSWarner Losh			end
372088b4f5fSWarner Losh		end
373088b4f5fSWarner Losh
374088b4f5fSWarner Losh		loader.delay(50000);
375088b4f5fSWarner Losh	until time <= 0
376088b4f5fSWarner Losh	core.boot();
377088b4f5fSWarner Losh
378088b4f5fSWarner Loshend
379088b4f5fSWarner Losh
380088b4f5fSWarner Loshfunction OnOff(str, b)
381088b4f5fSWarner Losh	if (b) then
382088b4f5fSWarner Losh		return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE);
383088b4f5fSWarner Losh	else
384088b4f5fSWarner Losh		return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE);
385088b4f5fSWarner Losh	end
386088b4f5fSWarner Loshend
387088b4f5fSWarner Losh
388088b4f5fSWarner Loshreturn menu
389