2 -- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
3 -- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org>
4 -- All rights reserved.
6 -- Redistribution and use in source and binary forms, with or without
7 -- modification, are permitted provided that the following conditions
9 -- 1. Redistributions of source code must retain the above copyright
10 -- notice, this list of conditions and the following disclaimer.
11 -- 2. Redistributions in binary form must reproduce the above copyright
12 -- notice, this list of conditions and the following disclaimer in the
13 -- documentation and/or other materials provided with the distribution.
15 -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 local core = require("core");
32 local color = require("color");
33 local config = require("config");
34 local screen = require("screen");
35 local drawer = require("drawer");
43 local OnOff = function(str, b)
45 return str .. color.escapef(color.GREEN) .. "On" ..
46 color.escapef(color.WHITE);
48 return str .. color.escapef(color.RED) .. "off" ..
49 color.escapef(color.WHITE);
55 -- Menu handlers take the current menu and selected entry as parameters,
56 -- and should return a boolean indicating whether execution should
57 -- continue or not. The return value may be omitted if this entry should
58 -- have no bearing on whether we continue or not, indicating that we
59 -- should just continue after execution.
60 [core.MENU_ENTRY] = function(current_menu, entry)
64 [core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry)
65 -- carousel (rotating) functionality
66 local carid = entry.carousel_id;
67 local caridx = config.getCarouselIndex(carid);
68 local choices = entry.items();
70 if (#choices > 0) then
71 caridx = (caridx % #choices) + 1;
72 config.setCarouselIndex(carid, caridx);
73 entry.func(caridx, choices[caridx], choices);
76 [core.MENU_SUBMENU] = function(current_menu, entry)
78 return menu.run(entry.submenu());
80 [core.MENU_RETURN] = function(current_menu, entry)
81 -- allow entry to have a function/side effect
82 if (entry.func ~= nil) then
88 -- loader menu tree is rooted at menu.welcome
92 -- return to welcome menu
94 entry_type = core.MENU_RETURN,
96 return "Back to main menu" ..
97 color.highlight(" [Backspace]");
103 entry_type = core.MENU_ENTRY,
105 return "Load System " .. color.highlight("D") ..
115 entry_type = core.MENU_SEPARATOR,
122 entry_type = core.MENU_SEPARATOR,
124 return "Boot Options:";
130 entry_type = core.MENU_ENTRY,
131 visible = core.isSystem386,
133 return OnOff(color.highlight("A") ..
143 entry_type = core.MENU_ENTRY,
145 return OnOff("Safe " .. color.highlight("M") ..
155 entry_type = core.MENU_ENTRY,
157 return OnOff(color.highlight("S") ..
158 "ingle user:", core.su);
161 core.setSingleUser();
167 entry_type = core.MENU_ENTRY,
169 return OnOff(color.highlight("V") ..
170 "erbose :", core.verbose);
182 local menu_entries = menu.welcome.all_entries;
183 -- Swap the first two menu items on single user boot
184 if (core.isSingleUserBoot()) then
185 -- We'll cache the swapped menu, for performance
186 if (menu.welcome.swapped_menu ~= nil) then
187 return menu.welcome.swapped_menu;
189 -- Shallow copy the table
190 menu_entries = core.shallowCopyTable(menu_entries);
192 -- Swap the first two menu entries
193 menu_entries[1], menu_entries[2] =
194 menu_entries[2], menu_entries[1];
196 -- Then set their names to their alternate names
197 menu_entries[1].name, menu_entries[2].name =
198 menu_entries[1].alternate_name,
199 menu_entries[2].alternate_name;
200 menu.welcome.swapped_menu = menu_entries;
207 entry_type = core.MENU_ENTRY,
209 return color.highlight("B") ..
211 color.highlight("[Enter]");
213 -- Not a standard menu entry function!
214 alternate_name = function()
215 return color.highlight("B") ..
219 core.setSingleUser(false);
227 entry_type = core.MENU_ENTRY,
229 return "Boot " .. color.highlight("S") ..
232 -- Not a standard menu entry function!
233 alternate_name = function()
234 return "Boot " .. color.highlight("S") ..
235 "ingle user " .. color.highlight("[Enter]");
238 core.setSingleUser(true);
244 -- escape to interpreter
246 entry_type = core.MENU_RETURN,
248 return color.highlight("Esc") ..
249 "ape to loader prompt";
252 loader.setenv("autoboot_delay", "NO");
254 alias = {core.KEYSTR_ESCAPE}
259 entry_type = core.MENU_ENTRY,
261 return color.highlight("R") .. "eboot";
264 loader.perform("reboot");
271 entry_type = core.MENU_SEPARATOR,
278 entry_type = core.MENU_SEPARATOR,
286 entry_type = core.MENU_CAROUSEL_ENTRY,
287 carousel_id = "kernel",
288 items = core.kernelList,
289 name = function(idx, choice, all_choices)
290 if (#all_choices == 0) then
294 local is_default = (idx == 1);
295 local kernel_name = "";
298 name_color = color.escapef(color.GREEN);
299 kernel_name = "default/";
301 name_color = color.escapef(color.BLUE);
303 kernel_name = kernel_name .. name_color ..
304 choice .. color.default();
305 return color.highlight("K") .. "ernel: " ..
306 kernel_name .. " (" .. idx .. " of " ..
309 func = function(idx, choice, all_choices)
310 config.selectkernel(choice);
317 entry_type = core.MENU_SUBMENU,
319 return "Boot " .. color.highlight("O") ..
323 return menu.boot_options;
332 if (menu.skip()) then
344 local alias_table = drawer.drawscreen(m);
350 local key = io.getchar();
352 -- Special key behaviors
353 if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and
354 (m ~= menu.welcome) then
356 elseif (key == core.KEY_ENTER) then
361 key = string.char(key)
362 -- check to see if key is an alias
363 local sel_entry = nil;
364 for k, v in pairs(alias_table) do
370 -- if we have an alias do the assigned action:
371 if (sel_entry ~= nil) then
373 local handler = menu.handlers[sel_entry.entry_type];
374 if (handler ~= nil) then
375 -- The handler's return value indicates whether
376 -- we need to exit this menu. An omitted return
377 -- value means "continue" by default.
378 cont = handler(m, sel_entry);
379 if (cont == nil) then
383 -- if we got an alias key the screen is out of date:
386 alias_table = drawer.drawscreen(m);
390 if (m == menu.welcome) then
392 print("Exiting menu!");
401 if (core.isSerialBoot()) then
404 local c = string.lower(loader.getenv("console") or "");
405 if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then
409 c = string.lower(loader.getenv("beastie_disable") or "");
410 print("beastie_disable", c);
414 function menu.autoboot()
415 if (menu.already_autoboot == true) then
418 menu.already_autoboot = true;
420 local ab = loader.getenv("autoboot_delay");
421 if (ab ~= nil) and (ab:lower() == "no") then
423 elseif (tonumber(ab) == -1) then
426 ab = tonumber(ab) or 10;
428 local x = loader.getenv("loader_menu_timeout_x") or 5;
429 local y = loader.getenv("loader_menu_timeout_y") or 22;
431 local endtime = loader.time() + ab;
435 time = endtime - loader.time();
436 screen.setcursor(x, y);
437 print("Autoboot in " .. time ..
438 " seconds, hit [Enter] to boot" ..
439 " or any other key to stop ");
441 if (io.ischar()) then
442 local ch = io.getchar();
443 if (ch == core.KEY_ENTER) then
446 -- erase autoboot msg
447 screen.setcursor(0, y);