xref: /freebsd/stand/lua/menu.lua (revision 088b4f5f323e73e5eb54b0e409b064ff5d46d221)
1*088b4f5fSWarner Losh--
2*088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3*088b4f5fSWarner Losh-- All rights reserved.
4*088b4f5fSWarner Losh--
5*088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without
6*088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions
7*088b4f5fSWarner Losh-- are met:
8*088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright
9*088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer.
10*088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright
11*088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer in the
12*088b4f5fSWarner Losh--    documentation and/or other materials provided with the distribution.
13*088b4f5fSWarner Losh--
14*088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*088b4f5fSWarner Losh-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*088b4f5fSWarner Losh-- SUCH DAMAGE.
25*088b4f5fSWarner Losh--
26*088b4f5fSWarner Losh-- $FreeBSD$
27*088b4f5fSWarner Losh--
28*088b4f5fSWarner Losh
29*088b4f5fSWarner Losh
30*088b4f5fSWarner Loshlocal menu = {};
31*088b4f5fSWarner Losh
32*088b4f5fSWarner Loshlocal core = require("core");
33*088b4f5fSWarner Loshlocal color = require("color");
34*088b4f5fSWarner Loshlocal config = require("config");
35*088b4f5fSWarner Loshlocal screen = require("screen");
36*088b4f5fSWarner Loshlocal drawer = require("drawer");
37*088b4f5fSWarner Losh
38*088b4f5fSWarner Loshlocal OnOff;
39*088b4f5fSWarner Loshlocal skip;
40*088b4f5fSWarner Loshlocal run;
41*088b4f5fSWarner Loshlocal autoboot;
42*088b4f5fSWarner Losh
43*088b4f5fSWarner Losh--loader menu tree:
44*088b4f5fSWarner Losh--rooted at menu.welcome
45*088b4f5fSWarner Losh--submenu declarations:
46*088b4f5fSWarner Loshlocal kernel_options;
47*088b4f5fSWarner Loshlocal boot_options;
48*088b4f5fSWarner Loshlocal welcome;
49*088b4f5fSWarner Losh
50*088b4f5fSWarner Loshmenu.kernel_options = {
51*088b4f5fSWarner Losh	-- this table is dynamically appended to when accessed
52*088b4f5fSWarner Losh	-- return to welcome menu
53*088b4f5fSWarner Losh	{
54*088b4f5fSWarner Losh		entry_type = "return",
55*088b4f5fSWarner Losh		name = function()
56*088b4f5fSWarner Losh			return "Back to main menu"..color.highlight(" [Backspace]");
57*088b4f5fSWarner Losh		end,
58*088b4f5fSWarner Losh		alias = {"\08"}
59*088b4f5fSWarner Losh	}
60*088b4f5fSWarner Losh};
61*088b4f5fSWarner Losh
62*088b4f5fSWarner Loshmenu.boot_options = {
63*088b4f5fSWarner Losh	-- return to welcome menu
64*088b4f5fSWarner Losh	{
65*088b4f5fSWarner Losh		entry_type = "return",
66*088b4f5fSWarner Losh		name = function()
67*088b4f5fSWarner Losh			return "Back to main menu"..color.highlight(" [Backspace]");
68*088b4f5fSWarner Losh		end,
69*088b4f5fSWarner Losh		alias = {"\08"}
70*088b4f5fSWarner Losh	},
71*088b4f5fSWarner Losh
72*088b4f5fSWarner Losh	-- load defaults
73*088b4f5fSWarner Losh	{
74*088b4f5fSWarner Losh		entry_type = "entry",
75*088b4f5fSWarner Losh		name = function()
76*088b4f5fSWarner Losh			return "Load System "..color.highlight("D").."efaults";
77*088b4f5fSWarner Losh		end,
78*088b4f5fSWarner Losh		func = function()
79*088b4f5fSWarner Losh			core.setDefaults()
80*088b4f5fSWarner Losh		end,
81*088b4f5fSWarner Losh		alias = {"d", "D"}
82*088b4f5fSWarner Losh	},
83*088b4f5fSWarner Losh
84*088b4f5fSWarner Losh	{
85*088b4f5fSWarner Losh		entry_type = "separator",
86*088b4f5fSWarner Losh		name = function()
87*088b4f5fSWarner Losh			return "";
88*088b4f5fSWarner Losh		end
89*088b4f5fSWarner Losh	},
90*088b4f5fSWarner Losh
91*088b4f5fSWarner Losh	{
92*088b4f5fSWarner Losh		entry_type = "separator",
93*088b4f5fSWarner Losh		name = function()
94*088b4f5fSWarner Losh			return "Boot Options:";
95*088b4f5fSWarner Losh		end
96*088b4f5fSWarner Losh	},
97*088b4f5fSWarner Losh
98*088b4f5fSWarner Losh	-- acpi
99*088b4f5fSWarner Losh	{
100*088b4f5fSWarner Losh		entry_type = "entry",
101*088b4f5fSWarner Losh		name = function()
102*088b4f5fSWarner Losh			return OnOff(color.highlight("A").."CPI       :", core.acpi);
103*088b4f5fSWarner Losh		end,
104*088b4f5fSWarner Losh		func = function()
105*088b4f5fSWarner Losh			core.setACPI();
106*088b4f5fSWarner Losh		end,
107*088b4f5fSWarner Losh		alias = {"a", "A"}
108*088b4f5fSWarner Losh	},
109*088b4f5fSWarner Losh	-- safe mode
110*088b4f5fSWarner Losh	{
111*088b4f5fSWarner Losh		entry_type = "entry",
112*088b4f5fSWarner Losh		name = function()
113*088b4f5fSWarner Losh			return OnOff("Safe "..color.highlight("M").."ode  :", core.sm);
114*088b4f5fSWarner Losh		end,
115*088b4f5fSWarner Losh		func = function()
116*088b4f5fSWarner Losh			core.setSafeMode();
117*088b4f5fSWarner Losh		end,
118*088b4f5fSWarner Losh		alias = {"m", "M"}
119*088b4f5fSWarner Losh	},
120*088b4f5fSWarner Losh	-- single user
121*088b4f5fSWarner Losh	{
122*088b4f5fSWarner Losh		entry_type = "entry",
123*088b4f5fSWarner Losh		name = function()
124*088b4f5fSWarner Losh			return OnOff(color.highlight("S").."ingle user:", core.su);
125*088b4f5fSWarner Losh		end,
126*088b4f5fSWarner Losh		func = function()
127*088b4f5fSWarner Losh			core.setSingleUser();
128*088b4f5fSWarner Losh		end,
129*088b4f5fSWarner Losh		alias = {"s", "S"}
130*088b4f5fSWarner Losh	},
131*088b4f5fSWarner Losh	-- verbose boot
132*088b4f5fSWarner Losh	{
133*088b4f5fSWarner Losh		entry_type = "entry",
134*088b4f5fSWarner Losh		name = function()
135*088b4f5fSWarner Losh			return OnOff(color.highlight("V").."erbose    :", core.verbose);
136*088b4f5fSWarner Losh		end,
137*088b4f5fSWarner Losh		func = function()
138*088b4f5fSWarner Losh			core.setVerbose();
139*088b4f5fSWarner Losh		end,
140*088b4f5fSWarner Losh		alias = {"v", "V"}
141*088b4f5fSWarner Losh	},
142*088b4f5fSWarner Losh};
143*088b4f5fSWarner Losh
144*088b4f5fSWarner Loshmenu.welcome = {
145*088b4f5fSWarner Losh	-- boot multi user
146*088b4f5fSWarner Losh	{
147*088b4f5fSWarner Losh		entry_type = "entry",
148*088b4f5fSWarner Losh		name = function()
149*088b4f5fSWarner Losh			return color.highlight("B").."oot Multi user "..color.highlight("[Enter]");
150*088b4f5fSWarner Losh		end,
151*088b4f5fSWarner Losh		func = function()
152*088b4f5fSWarner Losh			core.setSingleUser(false);
153*088b4f5fSWarner Losh			core.boot();
154*088b4f5fSWarner Losh		end,
155*088b4f5fSWarner Losh		alias = {"b", "B", "\013"}
156*088b4f5fSWarner Losh	},
157*088b4f5fSWarner Losh
158*088b4f5fSWarner Losh	-- boot single user
159*088b4f5fSWarner Losh	{
160*088b4f5fSWarner Losh		entry_type = "entry",
161*088b4f5fSWarner Losh		name = function()
162*088b4f5fSWarner Losh			return "Boot "..color.highlight("S").."ingle user";
163*088b4f5fSWarner Losh		end,
164*088b4f5fSWarner Losh		func = function()
165*088b4f5fSWarner Losh			core.setSingleUser(true);
166*088b4f5fSWarner Losh			core.boot();
167*088b4f5fSWarner Losh		end,
168*088b4f5fSWarner Losh		alias = {"s", "S"}
169*088b4f5fSWarner Losh	},
170*088b4f5fSWarner Losh
171*088b4f5fSWarner Losh	-- escape to interpreter
172*088b4f5fSWarner Losh	{
173*088b4f5fSWarner Losh		entry_type = "return",
174*088b4f5fSWarner Losh		name = function()
175*088b4f5fSWarner Losh			return color.highlight("Esc").."ape to lua interpreter";
176*088b4f5fSWarner Losh		end,
177*088b4f5fSWarner Losh		alias = {"\027"}
178*088b4f5fSWarner Losh	},
179*088b4f5fSWarner Losh
180*088b4f5fSWarner Losh	-- reboot
181*088b4f5fSWarner Losh	{
182*088b4f5fSWarner Losh		entry_type = "entry",
183*088b4f5fSWarner Losh		name = function()
184*088b4f5fSWarner Losh			return color.highlight("R").."eboot";
185*088b4f5fSWarner Losh		end,
186*088b4f5fSWarner Losh		func = function()
187*088b4f5fSWarner Losh			loader.perform("reboot");
188*088b4f5fSWarner Losh		end,
189*088b4f5fSWarner Losh		alias = {"r", "R"}
190*088b4f5fSWarner Losh	},
191*088b4f5fSWarner Losh
192*088b4f5fSWarner Losh
193*088b4f5fSWarner Losh	{
194*088b4f5fSWarner Losh		entry_type = "separator",
195*088b4f5fSWarner Losh		name = function()
196*088b4f5fSWarner Losh			return "";
197*088b4f5fSWarner Losh		end
198*088b4f5fSWarner Losh	},
199*088b4f5fSWarner Losh
200*088b4f5fSWarner Losh	{
201*088b4f5fSWarner Losh		entry_type = "separator",
202*088b4f5fSWarner Losh		name = function()
203*088b4f5fSWarner Losh			return "Options:";
204*088b4f5fSWarner Losh		end
205*088b4f5fSWarner Losh	},
206*088b4f5fSWarner Losh
207*088b4f5fSWarner Losh	-- kernel options
208*088b4f5fSWarner Losh	{
209*088b4f5fSWarner Losh		entry_type = "submenu",
210*088b4f5fSWarner Losh		name = function()
211*088b4f5fSWarner Losh			local kernels = core.kernelList();
212*088b4f5fSWarner Losh			if #kernels == 0 then
213*088b4f5fSWarner Losh				return "Kernels (not available)";
214*088b4f5fSWarner Losh			end
215*088b4f5fSWarner Losh			return color.highlight("K").."ernels";
216*088b4f5fSWarner Losh		end,
217*088b4f5fSWarner Losh		submenu = function()
218*088b4f5fSWarner Losh
219*088b4f5fSWarner Losh			-- dynamically build the kernel menu:
220*088b4f5fSWarner Losh			local kernels = core.kernelList();
221*088b4f5fSWarner Losh			for k, v in ipairs(kernels) do
222*088b4f5fSWarner Losh				menu.kernel_options[#menu.kernel_options + 1] = {
223*088b4f5fSWarner Losh					entry_type = "entry",
224*088b4f5fSWarner Losh					name = function()
225*088b4f5fSWarner Losh						return v;
226*088b4f5fSWarner Losh					end,
227*088b4f5fSWarner Losh					func = function()
228*088b4f5fSWarner Losh						config.reload(v);
229*088b4f5fSWarner Losh					end,
230*088b4f5fSWarner Losh					alias = {} -- automatically enumerated
231*088b4f5fSWarner Losh				}
232*088b4f5fSWarner Losh			end
233*088b4f5fSWarner Losh
234*088b4f5fSWarner Losh			return menu.kernel_options;
235*088b4f5fSWarner Losh		end,
236*088b4f5fSWarner Losh		alias = {"k", "K"}
237*088b4f5fSWarner Losh	},
238*088b4f5fSWarner Losh
239*088b4f5fSWarner Losh	-- boot options
240*088b4f5fSWarner Losh	{
241*088b4f5fSWarner Losh		entry_type = "submenu",
242*088b4f5fSWarner Losh		name = function()
243*088b4f5fSWarner Losh			return "Boot "..color.highlight("O").."ptions";
244*088b4f5fSWarner Losh		end,
245*088b4f5fSWarner Losh		submenu = function()
246*088b4f5fSWarner Losh			return menu.boot_options;
247*088b4f5fSWarner Losh		end,
248*088b4f5fSWarner Losh		alias = {"o", "O"}
249*088b4f5fSWarner Losh	}
250*088b4f5fSWarner Losh
251*088b4f5fSWarner Losh};
252*088b4f5fSWarner Losh
253*088b4f5fSWarner Loshfunction menu.run(m)
254*088b4f5fSWarner Losh
255*088b4f5fSWarner Losh	if (menu.skip()) then
256*088b4f5fSWarner Losh		core.autoboot();
257*088b4f5fSWarner Losh		return false;
258*088b4f5fSWarner Losh	end
259*088b4f5fSWarner Losh
260*088b4f5fSWarner Losh	if (m == nil) then
261*088b4f5fSWarner Losh		m = menu.welcome;
262*088b4f5fSWarner Losh	end
263*088b4f5fSWarner Losh
264*088b4f5fSWarner Losh	-- redraw screen
265*088b4f5fSWarner Losh	screen.clear();
266*088b4f5fSWarner Losh	screen.defcursor();
267*088b4f5fSWarner Losh	local alias_table = drawer.drawscreen(m);
268*088b4f5fSWarner Losh
269*088b4f5fSWarner Losh--	menu.autoboot();
270*088b4f5fSWarner Losh
271*088b4f5fSWarner Losh	cont = true;
272*088b4f5fSWarner Losh	while cont do
273*088b4f5fSWarner Losh		local key = string.char(io.getchar());
274*088b4f5fSWarner Losh
275*088b4f5fSWarner Losh		-- check to see if key is an alias
276*088b4f5fSWarner Losh		local sel_entry = nil;
277*088b4f5fSWarner Losh		for k, v in pairs(alias_table) do
278*088b4f5fSWarner Losh			if (key == k) then
279*088b4f5fSWarner Losh				sel_entry = v;
280*088b4f5fSWarner Losh			end
281*088b4f5fSWarner Losh		end
282*088b4f5fSWarner Losh
283*088b4f5fSWarner Losh		-- if we have an alias do the assigned action:
284*088b4f5fSWarner Losh		if(sel_entry ~= nil) then
285*088b4f5fSWarner Losh			if (sel_entry.entry_type == "entry") then
286*088b4f5fSWarner Losh				-- run function
287*088b4f5fSWarner Losh				sel_entry.func();
288*088b4f5fSWarner Losh			elseif (sel_entry.entry_type == "submenu") then
289*088b4f5fSWarner Losh				-- recurse
290*088b4f5fSWarner Losh				cont = menu.run(sel_entry.submenu());
291*088b4f5fSWarner Losh			elseif (sel_entry.entry_type == "return") then
292*088b4f5fSWarner Losh				-- break recurse
293*088b4f5fSWarner Losh				cont = false;
294*088b4f5fSWarner Losh			end
295*088b4f5fSWarner Losh			-- if we got an alias key the screen is out of date:
296*088b4f5fSWarner Losh			screen.clear();
297*088b4f5fSWarner Losh			screen.defcursor();
298*088b4f5fSWarner Losh			alias_table = drawer.drawscreen(m);
299*088b4f5fSWarner Losh		end
300*088b4f5fSWarner Losh	end
301*088b4f5fSWarner Losh
302*088b4f5fSWarner Losh	if (m == menu.welcome) then
303*088b4f5fSWarner Losh		screen.defcursor();
304*088b4f5fSWarner Losh		print("Exiting menu!");
305*088b4f5fSWarner Losh		return false;
306*088b4f5fSWarner Losh	end
307*088b4f5fSWarner Losh
308*088b4f5fSWarner Losh	return true;
309*088b4f5fSWarner Loshend
310*088b4f5fSWarner Losh
311*088b4f5fSWarner Loshfunction menu.skip()
312*088b4f5fSWarner Losh	if core.bootserial() then
313*088b4f5fSWarner Losh		return true;
314*088b4f5fSWarner Losh	end
315*088b4f5fSWarner Losh	local c = string.lower(loader.getenv("console") or "");
316*088b4f5fSWarner Losh	if (c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil then
317*088b4f5fSWarner Losh		return true;
318*088b4f5fSWarner Losh	end
319*088b4f5fSWarner Losh
320*088b4f5fSWarner Losh	c = string.lower(loader.getenv("beastie_disable") or "");
321*088b4f5fSWarner Losh	print("beastie_disable", c);
322*088b4f5fSWarner Losh	return c == "yes";
323*088b4f5fSWarner Loshend
324*088b4f5fSWarner Losh
325*088b4f5fSWarner Loshfunction menu.autoboot()
326*088b4f5fSWarner Losh	if menu.already_autoboot == true then
327*088b4f5fSWarner Losh		return;
328*088b4f5fSWarner Losh	end
329*088b4f5fSWarner Losh	menu.already_autoboot = true;
330*088b4f5fSWarner Losh
331*088b4f5fSWarner Losh	local ab = loader.getenv("autoboot_delay");
332*088b4f5fSWarner Losh	if ab == "NO" or ab == "no" then
333*088b4f5fSWarner Losh		core.boot();
334*088b4f5fSWarner Losh	end
335*088b4f5fSWarner Losh	ab = tonumber(ab) or 10;
336*088b4f5fSWarner Losh
337*088b4f5fSWarner Losh	local x = loader.getenv("loader_menu_timeout_x") or 5;
338*088b4f5fSWarner Losh	local y = loader.getenv("loader_menu_timeout_y") or 22;
339*088b4f5fSWarner Losh
340*088b4f5fSWarner Losh	local endtime = loader.time() + ab;
341*088b4f5fSWarner Losh	local time;
342*088b4f5fSWarner Losh
343*088b4f5fSWarner Losh	repeat
344*088b4f5fSWarner Losh		time = endtime - loader.time();
345*088b4f5fSWarner Losh		screen.setcursor(x, y);
346*088b4f5fSWarner Losh		print("Autoboot in "..time.." seconds, hit [Enter] to boot"
347*088b4f5fSWarner Losh			      .." or any other key to stop     ");
348*088b4f5fSWarner Losh		screen.defcursor();
349*088b4f5fSWarner Losh		if io.ischar() then
350*088b4f5fSWarner Losh			local ch = io.getchar();
351*088b4f5fSWarner Losh			if ch == 13 then
352*088b4f5fSWarner Losh				break;
353*088b4f5fSWarner Losh			else
354*088b4f5fSWarner Losh				-- prevent autoboot when escaping to interpreter
355*088b4f5fSWarner Losh				loader.setenv("autoboot_delay", "NO");
356*088b4f5fSWarner Losh				-- erase autoboot msg
357*088b4f5fSWarner Losh				screen.setcursor(0, y);
358*088b4f5fSWarner Losh				print("                                        "
359*088b4f5fSWarner Losh					      .."                                        ");
360*088b4f5fSWarner Losh				screen.defcursor();
361*088b4f5fSWarner Losh				return;
362*088b4f5fSWarner Losh			end
363*088b4f5fSWarner Losh		end
364*088b4f5fSWarner Losh
365*088b4f5fSWarner Losh		loader.delay(50000);
366*088b4f5fSWarner Losh	until time <= 0
367*088b4f5fSWarner Losh	core.boot();
368*088b4f5fSWarner Losh
369*088b4f5fSWarner Loshend
370*088b4f5fSWarner Losh
371*088b4f5fSWarner Loshfunction OnOff(str, b)
372*088b4f5fSWarner Losh	if (b) then
373*088b4f5fSWarner Losh		return str .. color.escapef(color.GREEN).."On"..color.escapef(color.WHITE);
374*088b4f5fSWarner Losh	else
375*088b4f5fSWarner Losh		return str .. color.escapef(color.RED).."off"..color.escapef(color.WHITE);
376*088b4f5fSWarner Losh	end
377*088b4f5fSWarner Loshend
378*088b4f5fSWarner Losh
379*088b4f5fSWarner Loshreturn menu
380