1088b4f5fSWarner Losh-- 272e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD 372e39d71SKyle Evans-- 4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 5e12ff891SKyle Evans-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 6088b4f5fSWarner Losh-- All rights reserved. 7088b4f5fSWarner Losh-- 8088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 9088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 10088b4f5fSWarner Losh-- are met: 11088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 12088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 13088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 14088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 15088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 16088b4f5fSWarner Losh-- 17088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27088b4f5fSWarner Losh-- SUCH DAMAGE. 28088b4f5fSWarner Losh-- 29088b4f5fSWarner Losh-- $FreeBSD$ 30088b4f5fSWarner Losh-- 31088b4f5fSWarner Losh 3276c75816SKyle Evanslocal cli = require("cli") 33aedd6be5SKyle Evanslocal core = require("core") 34aedd6be5SKyle Evanslocal color = require("color") 35aedd6be5SKyle Evanslocal config = require("config") 36aedd6be5SKyle Evanslocal screen = require("screen") 37aedd6be5SKyle Evanslocal drawer = require("drawer") 38088b4f5fSWarner Losh 39aedd6be5SKyle Evanslocal menu = {} 40c8518398SKyle Evans 41beafe961SKyle Evanslocal drawn_menu 4243f7d9d1SKyle Evanslocal return_menu_entry = { 4343f7d9d1SKyle Evans entry_type = core.MENU_RETURN, 4443f7d9d1SKyle Evans name = "Back to main menu" .. color.highlight(" [Backspace]"), 4543f7d9d1SKyle Evans} 46ca16d83fSKyle Evans 4704af4229SKyle Evanslocal function OnOff(str, value) 4804af4229SKyle Evans if value then 498ce1744fSKyle Evans return str .. color.escapefg(color.GREEN) .. "On" .. 506dd078dfSToomas Soome color.resetfg() 51e15abd1fSKyle Evans else 528ce1744fSKyle Evans return str .. color.escapefg(color.RED) .. "off" .. 536dd078dfSToomas Soome color.resetfg() 54e15abd1fSKyle Evans end 55e15abd1fSKyle Evansend 56e15abd1fSKyle Evans 579ed6f9efSKyle Evanslocal function bootenvSet(env) 587efc058fSKyle Evans loader.setenv("vfs.root.mountfrom", env) 597efc058fSKyle Evans loader.setenv("currdev", env .. ":") 607efc058fSKyle Evans config.reload() 617efc058fSKyle Evansend 627efc058fSKyle Evans 63b5746545SKyle Evans-- Module exports 648d415029SKyle Evansmenu.handlers = { 658d415029SKyle Evans -- Menu handlers take the current menu and selected entry as parameters, 668d415029SKyle Evans -- and should return a boolean indicating whether execution should 678d415029SKyle Evans -- continue or not. The return value may be omitted if this entry should 688d415029SKyle Evans -- have no bearing on whether we continue or not, indicating that we 698d415029SKyle Evans -- should just continue after execution. 70e2df27e3SKyle Evans [core.MENU_ENTRY] = function(_, entry) 718d415029SKyle Evans -- run function 72aedd6be5SKyle Evans entry.func() 738d415029SKyle Evans end, 74e2df27e3SKyle Evans [core.MENU_CAROUSEL_ENTRY] = function(_, entry) 758d415029SKyle Evans -- carousel (rotating) functionality 76aedd6be5SKyle Evans local carid = entry.carousel_id 77aedd6be5SKyle Evans local caridx = config.getCarouselIndex(carid) 784f437f9eSKyle Evans local choices = entry.items 794f437f9eSKyle Evans if type(choices) == "function" then 804f437f9eSKyle Evans choices = choices() 814f437f9eSKyle Evans end 829f71d421SKyle Evans if #choices > 0 then 83aedd6be5SKyle Evans caridx = (caridx % #choices) + 1 84aedd6be5SKyle Evans config.setCarouselIndex(carid, caridx) 85aedd6be5SKyle Evans entry.func(caridx, choices[caridx], choices) 868d415029SKyle Evans end 878d415029SKyle Evans end, 88e2df27e3SKyle Evans [core.MENU_SUBMENU] = function(_, entry) 89da9ab827SKyle Evans menu.process(entry.submenu) 908d415029SKyle Evans end, 91e2df27e3SKyle Evans [core.MENU_RETURN] = function(_, entry) 928d415029SKyle Evans -- allow entry to have a function/side effect 939f71d421SKyle Evans if entry.func ~= nil then 94aedd6be5SKyle Evans entry.func() 958d415029SKyle Evans end 96aedd6be5SKyle Evans return false 978d415029SKyle Evans end, 98aedd6be5SKyle Evans} 99280e990bSKyle Evans-- loader menu tree is rooted at menu.welcome 100088b4f5fSWarner Losh 1017efc058fSKyle Evansmenu.boot_environments = { 1027efc058fSKyle Evans entries = { 1037efc058fSKyle Evans -- return to welcome menu 10443f7d9d1SKyle Evans return_menu_entry, 1057efc058fSKyle Evans { 1067efc058fSKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 1077efc058fSKyle Evans carousel_id = "be_active", 1087efc058fSKyle Evans items = core.bootenvList, 1097efc058fSKyle Evans name = function(idx, choice, all_choices) 1107efc058fSKyle Evans if #all_choices == 0 then 1117efc058fSKyle Evans return "Active: " 1127efc058fSKyle Evans end 1137efc058fSKyle Evans 1147efc058fSKyle Evans local is_default = (idx == 1) 1157efc058fSKyle Evans local bootenv_name = "" 1167efc058fSKyle Evans local name_color 1177efc058fSKyle Evans if is_default then 1188ce1744fSKyle Evans name_color = color.escapefg(color.GREEN) 1197efc058fSKyle Evans else 1208ce1744fSKyle Evans name_color = color.escapefg(color.BLUE) 1217efc058fSKyle Evans end 1227efc058fSKyle Evans bootenv_name = bootenv_name .. name_color .. 1238ce1744fSKyle Evans choice .. color.resetfg() 1247efc058fSKyle Evans return color.highlight("A").."ctive: " .. 1257efc058fSKyle Evans bootenv_name .. " (" .. idx .. " of " .. 1267efc058fSKyle Evans #all_choices .. ")" 1277efc058fSKyle Evans end, 128e2df27e3SKyle Evans func = function(_, choice, _) 1297efc058fSKyle Evans bootenvSet(choice) 1307efc058fSKyle Evans end, 1317efc058fSKyle Evans alias = {"a", "A"}, 1327efc058fSKyle Evans }, 1337efc058fSKyle Evans { 1347efc058fSKyle Evans entry_type = core.MENU_ENTRY, 1357efc058fSKyle Evans name = function() 1367efc058fSKyle Evans return color.highlight("b") .. "ootfs: " .. 1377efc058fSKyle Evans core.bootenvDefault() 1387efc058fSKyle Evans end, 1397efc058fSKyle Evans func = function() 1407efc058fSKyle Evans -- Reset active boot environment to the default 1417efc058fSKyle Evans config.setCarouselIndex("be_active", 1) 1427efc058fSKyle Evans bootenvSet(core.bootenvDefault()) 1437efc058fSKyle Evans end, 1447efc058fSKyle Evans alias = {"b", "B"}, 1457efc058fSKyle Evans }, 1467efc058fSKyle Evans }, 1477efc058fSKyle Evans} 1487efc058fSKyle Evans 149088b4f5fSWarner Loshmenu.boot_options = { 150d8757746SKyle Evans entries = { 151088b4f5fSWarner Losh -- return to welcome menu 15243f7d9d1SKyle Evans return_menu_entry, 153088b4f5fSWarner Losh -- load defaults 154088b4f5fSWarner Losh { 155a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 156a51f9f0cSKyle Evans name = "Load System " .. color.highlight("D") .. 157a51f9f0cSKyle Evans "efaults", 158a51f9f0cSKyle Evans func = core.setDefaults, 1593cd5547bSKyle Evans alias = {"d", "D"}, 160088b4f5fSWarner Losh }, 161088b4f5fSWarner Losh { 162a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 163088b4f5fSWarner Losh }, 164088b4f5fSWarner Losh { 165a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 166a51f9f0cSKyle Evans name = "Boot Options:", 167088b4f5fSWarner Losh }, 168088b4f5fSWarner Losh -- acpi 169088b4f5fSWarner Losh { 170a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 171c1ab36f5SKyle Evans visible = core.isSystem386, 172088b4f5fSWarner Losh name = function() 173fd2b19b3SKyle Evans return OnOff(color.highlight("A") .. 174aedd6be5SKyle Evans "CPI :", core.acpi) 175088b4f5fSWarner Losh end, 176a51f9f0cSKyle Evans func = core.setACPI, 1773cd5547bSKyle Evans alias = {"a", "A"}, 178088b4f5fSWarner Losh }, 179088b4f5fSWarner Losh -- safe mode 180088b4f5fSWarner Losh { 181a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 182088b4f5fSWarner Losh name = function() 18357099121SKyle Evans return OnOff("Safe " .. color.highlight("M") .. 184aedd6be5SKyle Evans "ode :", core.sm) 185088b4f5fSWarner Losh end, 186a51f9f0cSKyle Evans func = core.setSafeMode, 1873cd5547bSKyle Evans alias = {"m", "M"}, 188088b4f5fSWarner Losh }, 189088b4f5fSWarner Losh -- single user 190088b4f5fSWarner Losh { 191a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 192088b4f5fSWarner Losh name = function() 193fd2b19b3SKyle Evans return OnOff(color.highlight("S") .. 194aedd6be5SKyle Evans "ingle user:", core.su) 195088b4f5fSWarner Losh end, 196a51f9f0cSKyle Evans func = core.setSingleUser, 1973cd5547bSKyle Evans alias = {"s", "S"}, 198088b4f5fSWarner Losh }, 199088b4f5fSWarner Losh -- verbose boot 200088b4f5fSWarner Losh { 201a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 202088b4f5fSWarner Losh name = function() 203fd2b19b3SKyle Evans return OnOff(color.highlight("V") .. 204aedd6be5SKyle Evans "erbose :", core.verbose) 205088b4f5fSWarner Losh end, 206a51f9f0cSKyle Evans func = core.setVerbose, 2073cd5547bSKyle Evans alias = {"v", "V"}, 208088b4f5fSWarner Losh }, 209d8757746SKyle Evans }, 210aedd6be5SKyle Evans} 211088b4f5fSWarner Losh 212088b4f5fSWarner Loshmenu.welcome = { 213303253e5SKyle Evans entries = function() 214aedd6be5SKyle Evans local menu_entries = menu.welcome.all_entries 215*d2187b39SRyan Moeller local multi_user = menu_entries.multi_user 216*d2187b39SRyan Moeller local single_user = menu_entries.single_user 217*d2187b39SRyan Moeller local boot_entry_1, boot_entry_2 2189f71d421SKyle Evans if core.isSingleUserBoot() then 219*d2187b39SRyan Moeller -- Swap the first two menu items on single user boot. 220*d2187b39SRyan Moeller -- We'll cache the alternate entries for performance. 221*d2187b39SRyan Moeller local alts = menu_entries.alts 222*d2187b39SRyan Moeller if alts == nil then 223*d2187b39SRyan Moeller single_user = core.deepCopyTable(single_user) 224*d2187b39SRyan Moeller multi_user = core.deepCopyTable(multi_user) 225*d2187b39SRyan Moeller single_user.name = single_user.alternate_name 226*d2187b39SRyan Moeller multi_user.name = multi_user.alternate_name 227*d2187b39SRyan Moeller menu_entries.alts = { 228*d2187b39SRyan Moeller single_user = single_user, 229*d2187b39SRyan Moeller multi_user = multi_user, 230*d2187b39SRyan Moeller } 231*d2187b39SRyan Moeller else 232*d2187b39SRyan Moeller single_user = alts.single_user 233*d2187b39SRyan Moeller multi_user = alts.multi_user 2349a0904b0SKyle Evans end 235*d2187b39SRyan Moeller boot_entry_1, boot_entry_2 = single_user, multi_user 236*d2187b39SRyan Moeller else 237*d2187b39SRyan Moeller boot_entry_1, boot_entry_2 = multi_user, single_user 238303253e5SKyle Evans end 239*d2187b39SRyan Moeller return { 240*d2187b39SRyan Moeller boot_entry_1, 241*d2187b39SRyan Moeller boot_entry_2, 242*d2187b39SRyan Moeller menu_entries.prompt, 243*d2187b39SRyan Moeller menu_entries.reboot, 244*d2187b39SRyan Moeller { 245*d2187b39SRyan Moeller entry_type = core.MENU_SEPARATOR, 246*d2187b39SRyan Moeller }, 247*d2187b39SRyan Moeller { 248*d2187b39SRyan Moeller entry_type = core.MENU_SEPARATOR, 249*d2187b39SRyan Moeller name = "Options:", 250*d2187b39SRyan Moeller }, 251*d2187b39SRyan Moeller menu_entries.kernel_options, 252*d2187b39SRyan Moeller menu_entries.boot_options, 253*d2187b39SRyan Moeller menu_entries.boot_envs, 254*d2187b39SRyan Moeller menu_entries.chainload, 255*d2187b39SRyan Moeller } 256303253e5SKyle Evans end, 257303253e5SKyle Evans all_entries = { 258*d2187b39SRyan Moeller multi_user = { 259a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 260a51f9f0cSKyle Evans name = color.highlight("B") .. "oot Multi user " .. 261a51f9f0cSKyle Evans color.highlight("[Enter]"), 2625c1b5165SKyle Evans -- Not a standard menu entry function! 263a51f9f0cSKyle Evans alternate_name = color.highlight("B") .. 264a51f9f0cSKyle Evans "oot Multi user", 265088b4f5fSWarner Losh func = function() 266aedd6be5SKyle Evans core.setSingleUser(false) 267aedd6be5SKyle Evans core.boot() 268088b4f5fSWarner Losh end, 2693cd5547bSKyle Evans alias = {"b", "B"}, 270088b4f5fSWarner Losh }, 271*d2187b39SRyan Moeller single_user = { 272a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 273a51f9f0cSKyle Evans name = "Boot " .. color.highlight("S") .. "ingle user", 2745c1b5165SKyle Evans -- Not a standard menu entry function! 275a51f9f0cSKyle Evans alternate_name = "Boot " .. color.highlight("S") .. 276a51f9f0cSKyle Evans "ingle user " .. color.highlight("[Enter]"), 277088b4f5fSWarner Losh func = function() 278aedd6be5SKyle Evans core.setSingleUser(true) 279aedd6be5SKyle Evans core.boot() 280088b4f5fSWarner Losh end, 2813cd5547bSKyle Evans alias = {"s", "S"}, 282088b4f5fSWarner Losh }, 283*d2187b39SRyan Moeller prompt = { 284a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 285a51f9f0cSKyle Evans name = color.highlight("Esc") .. "ape to loader prompt", 286ef625845SKyle Evans func = function() 287aedd6be5SKyle Evans loader.setenv("autoboot_delay", "NO") 288ef625845SKyle Evans end, 2893cd5547bSKyle Evans alias = {core.KEYSTR_ESCAPE}, 290088b4f5fSWarner Losh }, 291*d2187b39SRyan Moeller reboot = { 292a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 293a51f9f0cSKyle Evans name = color.highlight("R") .. "eboot", 294088b4f5fSWarner Losh func = function() 295aedd6be5SKyle Evans loader.perform("reboot") 296088b4f5fSWarner Losh end, 2973cd5547bSKyle Evans alias = {"r", "R"}, 298088b4f5fSWarner Losh }, 299*d2187b39SRyan Moeller kernel_options = { 300a7cf0562SKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 301ada26c4aSKyle Evans carousel_id = "kernel", 302ada26c4aSKyle Evans items = core.kernelList, 303ada26c4aSKyle Evans name = function(idx, choice, all_choices) 3049f71d421SKyle Evans if #all_choices == 0 then 305aedd6be5SKyle Evans return "Kernel: " 306088b4f5fSWarner Losh end 307b1b1f2b8SKyle Evans 308aedd6be5SKyle Evans local is_default = (idx == 1) 309aedd6be5SKyle Evans local kernel_name = "" 310aedd6be5SKyle Evans local name_color 3119f71d421SKyle Evans if is_default then 3128ce1744fSKyle Evans name_color = color.escapefg(color.GREEN) 313aedd6be5SKyle Evans kernel_name = "default/" 314bcf48a15SKyle Evans else 3158ce1744fSKyle Evans name_color = color.escapefg(color.BLUE) 316b1b1f2b8SKyle Evans end 317fd2b19b3SKyle Evans kernel_name = kernel_name .. name_color .. 3188ce1744fSKyle Evans choice .. color.resetfg() 319fd2b19b3SKyle Evans return color.highlight("K") .. "ernel: " .. 320fd2b19b3SKyle Evans kernel_name .. " (" .. idx .. " of " .. 321aedd6be5SKyle Evans #all_choices .. ")" 322088b4f5fSWarner Losh end, 323e2df27e3SKyle Evans func = function(_, choice, _) 324e414851fSKyle Evans if loader.getenv("kernelname") ~= nil then 325e414851fSKyle Evans loader.perform("unload") 326e414851fSKyle Evans end 327322a2dddSKyle Evans config.selectKernel(choice) 328088b4f5fSWarner Losh end, 3293cd5547bSKyle Evans alias = {"k", "K"}, 330088b4f5fSWarner Losh }, 331*d2187b39SRyan Moeller boot_options = { 332a7cf0562SKyle Evans entry_type = core.MENU_SUBMENU, 333a51f9f0cSKyle Evans name = "Boot " .. color.highlight("O") .. "ptions", 3349a28f948SKyle Evans submenu = menu.boot_options, 3353cd5547bSKyle Evans alias = {"o", "O"}, 336d8757746SKyle Evans }, 337*d2187b39SRyan Moeller boot_envs = { 3387efc058fSKyle Evans entry_type = core.MENU_SUBMENU, 3397efc058fSKyle Evans visible = function() 3407efc058fSKyle Evans return core.isZFSBoot() and 3417efc058fSKyle Evans #core.bootenvList() > 1 3427efc058fSKyle Evans end, 3437efc058fSKyle Evans name = "Boot " .. color.highlight("E") .. "nvironments", 3447efc058fSKyle Evans submenu = menu.boot_environments, 3457efc058fSKyle Evans alias = {"e", "E"}, 3467efc058fSKyle Evans }, 347*d2187b39SRyan Moeller chainload = { 348bdf12807SKyle Evans entry_type = core.MENU_ENTRY, 349bdf12807SKyle Evans name = function() 350bdf12807SKyle Evans return 'Chain' .. color.highlight("L") .. 351bdf12807SKyle Evans "oad " .. loader.getenv('chain_disk') 352bdf12807SKyle Evans end, 353bdf12807SKyle Evans func = function() 354bdf12807SKyle Evans loader.perform("chain " .. 355bdf12807SKyle Evans loader.getenv('chain_disk')) 356bdf12807SKyle Evans end, 357bdf12807SKyle Evans visible = function() 358bdf12807SKyle Evans return loader.getenv('chain_disk') ~= nil 359bdf12807SKyle Evans end, 360bdf12807SKyle Evans alias = {"l", "L"}, 361bdf12807SKyle Evans }, 362d8757746SKyle Evans }, 363aedd6be5SKyle Evans} 364088b4f5fSWarner Losh 36520a81676SKyle Evansmenu.default = menu.welcome 36628384160SKyle Evans-- current_alias_table will be used to keep our alias table consistent across 36728384160SKyle Evans-- screen redraws, instead of relying on whatever triggered the redraw to update 36828384160SKyle Evans-- the local alias_table in menu.process. 36928384160SKyle Evansmenu.current_alias_table = {} 37020a81676SKyle Evans 3712a11b810SKyle Evansfunction menu.draw(menudef) 372beafe961SKyle Evans -- Clear the screen, reset the cursor, then draw 373aedd6be5SKyle Evans screen.clear() 3742a11b810SKyle Evans menu.current_alias_table = drawer.drawscreen(menudef) 3752a11b810SKyle Evans drawn_menu = menudef 376decacd91SKyle Evans screen.defcursor() 37728384160SKyle Evansend 37828384160SKyle Evans 379ca16d83fSKyle Evans-- 'keypress' allows the caller to indicate that a key has been pressed that we 380ca16d83fSKyle Evans-- should process as our initial input. 3812a11b810SKyle Evansfunction menu.process(menudef, keypress) 3822a11b810SKyle Evans assert(menudef ~= nil) 38328384160SKyle Evans 3842a11b810SKyle Evans if drawn_menu ~= menudef then 3852a11b810SKyle Evans menu.draw(menudef) 3867dcffa90SKyle Evans end 387ca16d83fSKyle Evans 388da9ab827SKyle Evans while true do 389ca16d83fSKyle Evans local key = keypress or io.getchar() 390ca16d83fSKyle Evans keypress = nil 391088b4f5fSWarner Losh 392b458bf0dSKyle Evans -- Special key behaviors 3939f71d421SKyle Evans if (key == core.KEY_BACKSPACE or key == core.KEY_DELETE) and 3942a11b810SKyle Evans menudef ~= menu.default then 395aedd6be5SKyle Evans break 3969f71d421SKyle Evans elseif key == core.KEY_ENTER then 397aedd6be5SKyle Evans core.boot() 398041929aaSKyle Evans -- Should not return. If it does, escape menu handling 399041929aaSKyle Evans -- and drop to loader prompt. 400041929aaSKyle Evans return false 401abc4f7e7SKyle Evans end 402abc4f7e7SKyle Evans 403abc4f7e7SKyle Evans key = string.char(key) 404088b4f5fSWarner Losh -- check to see if key is an alias 405aedd6be5SKyle Evans local sel_entry = nil 40628384160SKyle Evans for k, v in pairs(menu.current_alias_table) do 4079f71d421SKyle Evans if key == k then 408aedd6be5SKyle Evans sel_entry = v 40928384160SKyle Evans break 410088b4f5fSWarner Losh end 411088b4f5fSWarner Losh end 412088b4f5fSWarner Losh 413088b4f5fSWarner Losh -- if we have an alias do the assigned action: 4149f71d421SKyle Evans if sel_entry ~= nil then 415aedd6be5SKyle Evans local handler = menu.handlers[sel_entry.entry_type] 4162a11b810SKyle Evans assert(handler ~= nil) 417da9ab827SKyle Evans -- The handler's return value indicates if we 418da9ab827SKyle Evans -- need to exit this menu. An omitted or true 419da9ab827SKyle Evans -- return value means to continue. 4202a11b810SKyle Evans if handler(menudef, sel_entry) == false then 421da9ab827SKyle Evans return 422aefcaa7eSKyle Evans end 42328384160SKyle Evans -- If we got an alias key the screen is out of date... 42428384160SKyle Evans -- redraw it. 4252a11b810SKyle Evans menu.draw(menudef) 426088b4f5fSWarner Losh end 427088b4f5fSWarner Losh end 428088b4f5fSWarner Loshend 429088b4f5fSWarner Losh 430da9ab827SKyle Evansfunction menu.run() 431041929aaSKyle Evans local autoboot_key 432c84dbc53SKyle Evans local delay = loader.getenv("autoboot_delay") 433c84dbc53SKyle Evans 434c84dbc53SKyle Evans if delay ~= nil and delay:lower() == "no" then 435c84dbc53SKyle Evans delay = nil 436c84dbc53SKyle Evans else 437c84dbc53SKyle Evans delay = tonumber(delay) or 10 438c84dbc53SKyle Evans end 439c84dbc53SKyle Evans 440c84dbc53SKyle Evans if delay == -1 then 441c84dbc53SKyle Evans core.boot() 442c84dbc53SKyle Evans return 443c84dbc53SKyle Evans end 444c84dbc53SKyle Evans 445beafe961SKyle Evans menu.draw(menu.default) 446c84dbc53SKyle Evans 447041929aaSKyle Evans if delay ~= nil then 448041929aaSKyle Evans autoboot_key = menu.autoboot(delay) 449041929aaSKyle Evans 450041929aaSKyle Evans -- autoboot_key should return the key pressed. It will only 451041929aaSKyle Evans -- return nil if we hit the timeout and executed the timeout 452041929aaSKyle Evans -- command. Bail out. 453041929aaSKyle Evans if autoboot_key == nil then 454041929aaSKyle Evans return 455041929aaSKyle Evans end 456041929aaSKyle Evans end 457ca16d83fSKyle Evans 458ca16d83fSKyle Evans menu.process(menu.default, autoboot_key) 459beafe961SKyle Evans drawn_menu = nil 460da9ab827SKyle Evans 461da9ab827SKyle Evans screen.defcursor() 462da9ab827SKyle Evans print("Exiting menu!") 463088b4f5fSWarner Loshend 464088b4f5fSWarner Losh 465c84dbc53SKyle Evansfunction menu.autoboot(delay) 4661495c98fSKyle Evans local x = loader.getenv("loader_menu_timeout_x") or 4 4671495c98fSKyle Evans local y = loader.getenv("loader_menu_timeout_y") or 23 468c84dbc53SKyle Evans local endtime = loader.time() + delay 469aedd6be5SKyle Evans local time 4703244729fSKyle Evans local last 471088b4f5fSWarner Losh repeat 472aedd6be5SKyle Evans time = endtime - loader.time() 4733244729fSKyle Evans if last == nil or last ~= time then 4743244729fSKyle Evans last = time 475aedd6be5SKyle Evans screen.setcursor(x, y) 47657099121SKyle Evans print("Autoboot in " .. time .. 47757099121SKyle Evans " seconds, hit [Enter] to boot" .. 478aedd6be5SKyle Evans " or any other key to stop ") 479aedd6be5SKyle Evans screen.defcursor() 4803244729fSKyle Evans end 4819f71d421SKyle Evans if io.ischar() then 482aedd6be5SKyle Evans local ch = io.getchar() 4839f71d421SKyle Evans if ch == core.KEY_ENTER then 484aedd6be5SKyle Evans break 485088b4f5fSWarner Losh else 486088b4f5fSWarner Losh -- erase autoboot msg 487aedd6be5SKyle Evans screen.setcursor(0, y) 48866964bbcSKyle Evans print(string.rep(" ", 80)) 489aedd6be5SKyle Evans screen.defcursor() 49012b95c84SKyle Evans return ch 491088b4f5fSWarner Losh end 492088b4f5fSWarner Losh end 493088b4f5fSWarner Losh 494aedd6be5SKyle Evans loader.delay(50000) 495aedd6be5SKyle Evans until time <= 0 496088b4f5fSWarner Losh 497a76f8a5bSKyle Evans local cmd = loader.getenv("menu_timeout_command") or "boot" 498e9c3ceb1SKyle Evans cli_execute_unparsed(cmd) 499041929aaSKyle Evans return nil 500088b4f5fSWarner Loshend 501088b4f5fSWarner Losh 50276c75816SKyle Evans-- CLI commands 5038f7f3d08SKyle Evansfunction cli.menu() 50476c75816SKyle Evans menu.run() 50576c75816SKyle Evansend 50676c75816SKyle Evans 507aedd6be5SKyle Evansreturn menu 508