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 31*aedd6be5SKyle Evanslocal core = require("core") 32*aedd6be5SKyle Evanslocal color = require("color") 33*aedd6be5SKyle Evanslocal config = require("config") 34*aedd6be5SKyle Evanslocal screen = require("screen") 35*aedd6be5SKyle Evanslocal drawer = require("drawer") 36088b4f5fSWarner Losh 37*aedd6be5SKyle Evanslocal menu = {} 38c8518398SKyle Evans 39*aedd6be5SKyle Evanslocal skip 40*aedd6be5SKyle Evanslocal run 41*aedd6be5SKyle Evanslocal autoboot 42088b4f5fSWarner Losh 43e15abd1fSKyle Evanslocal OnOff = function(str, b) 44e15abd1fSKyle Evans if (b) then 45e15abd1fSKyle Evans return str .. color.escapef(color.GREEN) .. "On" .. 46*aedd6be5SKyle Evans color.escapef(color.WHITE) 47e15abd1fSKyle Evans else 48e15abd1fSKyle Evans return str .. color.escapef(color.RED) .. "off" .. 49*aedd6be5SKyle Evans color.escapef(color.WHITE) 50e15abd1fSKyle Evans end 51e15abd1fSKyle Evansend 52e15abd1fSKyle Evans 53b5746545SKyle Evans-- Module exports 548d415029SKyle Evansmenu.handlers = { 558d415029SKyle Evans -- Menu handlers take the current menu and selected entry as parameters, 568d415029SKyle Evans -- and should return a boolean indicating whether execution should 578d415029SKyle Evans -- continue or not. The return value may be omitted if this entry should 588d415029SKyle Evans -- have no bearing on whether we continue or not, indicating that we 598d415029SKyle Evans -- should just continue after execution. 608d415029SKyle Evans [core.MENU_ENTRY] = function(current_menu, entry) 618d415029SKyle Evans -- run function 62*aedd6be5SKyle Evans entry.func() 638d415029SKyle Evans end, 648d415029SKyle Evans [core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry) 658d415029SKyle Evans -- carousel (rotating) functionality 66*aedd6be5SKyle Evans local carid = entry.carousel_id 67*aedd6be5SKyle Evans local caridx = config.getCarouselIndex(carid) 68*aedd6be5SKyle Evans local choices = entry.items() 698d415029SKyle Evans 708d415029SKyle Evans if (#choices > 0) then 71*aedd6be5SKyle Evans caridx = (caridx % #choices) + 1 72*aedd6be5SKyle Evans config.setCarouselIndex(carid, caridx) 73*aedd6be5SKyle Evans entry.func(caridx, choices[caridx], choices) 748d415029SKyle Evans end 758d415029SKyle Evans end, 768d415029SKyle Evans [core.MENU_SUBMENU] = function(current_menu, entry) 778d415029SKyle Evans -- recurse 78*aedd6be5SKyle Evans return menu.run(entry.submenu()) 798d415029SKyle Evans end, 808d415029SKyle Evans [core.MENU_RETURN] = function(current_menu, entry) 818d415029SKyle Evans -- allow entry to have a function/side effect 828d415029SKyle Evans if (entry.func ~= nil) then 83*aedd6be5SKyle Evans entry.func() 848d415029SKyle Evans end 85*aedd6be5SKyle Evans return false 868d415029SKyle Evans end, 87*aedd6be5SKyle Evans} 88280e990bSKyle Evans-- loader menu tree is rooted at menu.welcome 89088b4f5fSWarner Losh 90088b4f5fSWarner Loshmenu.boot_options = { 91d8757746SKyle Evans entries = { 92088b4f5fSWarner Losh -- return to welcome menu 93088b4f5fSWarner Losh { 94a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 95088b4f5fSWarner Losh name = function() 9657099121SKyle Evans return "Back to main menu" .. 97*aedd6be5SKyle Evans color.highlight(" [Backspace]") 981666dfc0SKyle Evans end 99088b4f5fSWarner Losh }, 100088b4f5fSWarner Losh 101088b4f5fSWarner Losh -- load defaults 102088b4f5fSWarner Losh { 103a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 104088b4f5fSWarner Losh name = function() 10557099121SKyle Evans return "Load System " .. color.highlight("D") .. 106*aedd6be5SKyle Evans "efaults" 107088b4f5fSWarner Losh end, 108088b4f5fSWarner Losh func = function() 109*aedd6be5SKyle Evans core.setDefaults() 110088b4f5fSWarner Losh end, 111088b4f5fSWarner Losh alias = {"d", "D"} 112088b4f5fSWarner Losh }, 113088b4f5fSWarner Losh 114088b4f5fSWarner Losh { 115a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 116088b4f5fSWarner Losh name = function() 117*aedd6be5SKyle Evans return "" 118088b4f5fSWarner Losh end 119088b4f5fSWarner Losh }, 120088b4f5fSWarner Losh 121088b4f5fSWarner Losh { 122a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 123088b4f5fSWarner Losh name = function() 124*aedd6be5SKyle Evans return "Boot Options:" 125088b4f5fSWarner Losh end 126088b4f5fSWarner Losh }, 127088b4f5fSWarner Losh 128088b4f5fSWarner Losh -- acpi 129088b4f5fSWarner Losh { 130a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 131c1ab36f5SKyle Evans visible = core.isSystem386, 132088b4f5fSWarner Losh name = function() 133fd2b19b3SKyle Evans return OnOff(color.highlight("A") .. 134*aedd6be5SKyle Evans "CPI :", core.acpi) 135088b4f5fSWarner Losh end, 136088b4f5fSWarner Losh func = function() 137*aedd6be5SKyle Evans core.setACPI() 138088b4f5fSWarner Losh end, 139088b4f5fSWarner Losh alias = {"a", "A"} 140088b4f5fSWarner Losh }, 141088b4f5fSWarner Losh -- safe mode 142088b4f5fSWarner Losh { 143a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 144088b4f5fSWarner Losh name = function() 14557099121SKyle Evans return OnOff("Safe " .. color.highlight("M") .. 146*aedd6be5SKyle Evans "ode :", core.sm) 147088b4f5fSWarner Losh end, 148088b4f5fSWarner Losh func = function() 149*aedd6be5SKyle Evans core.setSafeMode() 150088b4f5fSWarner Losh end, 151088b4f5fSWarner Losh alias = {"m", "M"} 152088b4f5fSWarner Losh }, 153088b4f5fSWarner Losh -- single user 154088b4f5fSWarner Losh { 155a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 156088b4f5fSWarner Losh name = function() 157fd2b19b3SKyle Evans return OnOff(color.highlight("S") .. 158*aedd6be5SKyle Evans "ingle user:", core.su) 159088b4f5fSWarner Losh end, 160088b4f5fSWarner Losh func = function() 161*aedd6be5SKyle Evans core.setSingleUser() 162088b4f5fSWarner Losh end, 163088b4f5fSWarner Losh alias = {"s", "S"} 164088b4f5fSWarner Losh }, 165088b4f5fSWarner Losh -- verbose boot 166088b4f5fSWarner Losh { 167a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 168088b4f5fSWarner Losh name = function() 169fd2b19b3SKyle Evans return OnOff(color.highlight("V") .. 170*aedd6be5SKyle Evans "erbose :", core.verbose) 171088b4f5fSWarner Losh end, 172088b4f5fSWarner Losh func = function() 173*aedd6be5SKyle Evans core.setVerbose() 174088b4f5fSWarner Losh end, 175088b4f5fSWarner Losh alias = {"v", "V"} 176088b4f5fSWarner Losh }, 177d8757746SKyle Evans }, 178*aedd6be5SKyle Evans} 179088b4f5fSWarner Losh 180088b4f5fSWarner Loshmenu.welcome = { 181303253e5SKyle Evans entries = function() 182*aedd6be5SKyle Evans local menu_entries = menu.welcome.all_entries 183303253e5SKyle Evans -- Swap the first two menu items on single user boot 184303253e5SKyle Evans if (core.isSingleUserBoot()) then 1859a0904b0SKyle Evans -- We'll cache the swapped menu, for performance 1869a0904b0SKyle Evans if (menu.welcome.swapped_menu ~= nil) then 187*aedd6be5SKyle Evans return menu.welcome.swapped_menu 1889a0904b0SKyle Evans end 1895c1b5165SKyle Evans -- Shallow copy the table 190*aedd6be5SKyle Evans menu_entries = core.shallowCopyTable(menu_entries) 1915c1b5165SKyle Evans 1929a0904b0SKyle Evans -- Swap the first two menu entries 1934b6da14cSKyle Evans menu_entries[1], menu_entries[2] = 194*aedd6be5SKyle Evans menu_entries[2], menu_entries[1] 195303253e5SKyle Evans 1969a0904b0SKyle Evans -- Then set their names to their alternate names 1979a0904b0SKyle Evans menu_entries[1].name, menu_entries[2].name = 1989a0904b0SKyle Evans menu_entries[1].alternate_name, 199*aedd6be5SKyle Evans menu_entries[2].alternate_name 200*aedd6be5SKyle Evans menu.welcome.swapped_menu = menu_entries 201303253e5SKyle Evans end 202*aedd6be5SKyle Evans return menu_entries 203303253e5SKyle Evans end, 204303253e5SKyle Evans all_entries = { 205088b4f5fSWarner Losh -- boot multi user 206088b4f5fSWarner Losh { 207a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 208088b4f5fSWarner Losh name = function() 209fd2b19b3SKyle Evans return color.highlight("B") .. 210fd2b19b3SKyle Evans "oot Multi user " .. 211*aedd6be5SKyle Evans color.highlight("[Enter]") 212088b4f5fSWarner Losh end, 2135c1b5165SKyle Evans -- Not a standard menu entry function! 2145c1b5165SKyle Evans alternate_name = function() 2155c1b5165SKyle Evans return color.highlight("B") .. 216*aedd6be5SKyle Evans "oot Multi user" 2175c1b5165SKyle Evans end, 218088b4f5fSWarner Losh func = function() 219*aedd6be5SKyle Evans core.setSingleUser(false) 220*aedd6be5SKyle Evans core.boot() 221088b4f5fSWarner Losh end, 222b458bf0dSKyle Evans alias = {"b", "B"} 223088b4f5fSWarner Losh }, 224088b4f5fSWarner Losh 225088b4f5fSWarner Losh -- boot single user 226088b4f5fSWarner Losh { 227a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 228088b4f5fSWarner Losh name = function() 229fd2b19b3SKyle Evans return "Boot " .. color.highlight("S") .. 230*aedd6be5SKyle Evans "ingle user" 231088b4f5fSWarner Losh end, 2325c1b5165SKyle Evans -- Not a standard menu entry function! 2335c1b5165SKyle Evans alternate_name = function() 2345c1b5165SKyle Evans return "Boot " .. color.highlight("S") .. 235*aedd6be5SKyle Evans "ingle user " .. color.highlight("[Enter]") 2365c1b5165SKyle Evans end, 237088b4f5fSWarner Losh func = function() 238*aedd6be5SKyle Evans core.setSingleUser(true) 239*aedd6be5SKyle Evans core.boot() 240088b4f5fSWarner Losh end, 241088b4f5fSWarner Losh alias = {"s", "S"} 242088b4f5fSWarner Losh }, 243088b4f5fSWarner Losh 244088b4f5fSWarner Losh -- escape to interpreter 245088b4f5fSWarner Losh { 246a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 247088b4f5fSWarner Losh name = function() 248fd2b19b3SKyle Evans return color.highlight("Esc") .. 249*aedd6be5SKyle Evans "ape to loader prompt" 250088b4f5fSWarner Losh end, 251ef625845SKyle Evans func = function() 252*aedd6be5SKyle Evans loader.setenv("autoboot_delay", "NO") 253ef625845SKyle Evans end, 25439006570SKyle Evans alias = {core.KEYSTR_ESCAPE} 255088b4f5fSWarner Losh }, 256088b4f5fSWarner Losh 257088b4f5fSWarner Losh -- reboot 258088b4f5fSWarner Losh { 259a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 260088b4f5fSWarner Losh name = function() 261*aedd6be5SKyle Evans return color.highlight("R") .. "eboot" 262088b4f5fSWarner Losh end, 263088b4f5fSWarner Losh func = function() 264*aedd6be5SKyle Evans loader.perform("reboot") 265088b4f5fSWarner Losh end, 266088b4f5fSWarner Losh alias = {"r", "R"} 267088b4f5fSWarner Losh }, 268088b4f5fSWarner Losh 269088b4f5fSWarner Losh 270088b4f5fSWarner Losh { 271a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 272088b4f5fSWarner Losh name = function() 273*aedd6be5SKyle Evans return "" 274088b4f5fSWarner Losh end 275088b4f5fSWarner Losh }, 276088b4f5fSWarner Losh 277088b4f5fSWarner Losh { 278a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 279088b4f5fSWarner Losh name = function() 280*aedd6be5SKyle Evans return "Options:" 281088b4f5fSWarner Losh end 282088b4f5fSWarner Losh }, 283088b4f5fSWarner Losh 284088b4f5fSWarner Losh -- kernel options 285088b4f5fSWarner Losh { 286a7cf0562SKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 287ada26c4aSKyle Evans carousel_id = "kernel", 288ada26c4aSKyle Evans items = core.kernelList, 289ada26c4aSKyle Evans name = function(idx, choice, all_choices) 29024a1bd54SKyle Evans if (#all_choices == 0) then 291*aedd6be5SKyle Evans return "Kernel: " 292088b4f5fSWarner Losh end 293b1b1f2b8SKyle Evans 294*aedd6be5SKyle Evans local is_default = (idx == 1) 295*aedd6be5SKyle Evans local kernel_name = "" 296*aedd6be5SKyle Evans local name_color 29724a1bd54SKyle Evans if (is_default) then 298*aedd6be5SKyle Evans name_color = color.escapef(color.GREEN) 299*aedd6be5SKyle Evans kernel_name = "default/" 300bcf48a15SKyle Evans else 301*aedd6be5SKyle Evans name_color = color.escapef(color.BLUE) 302b1b1f2b8SKyle Evans end 303fd2b19b3SKyle Evans kernel_name = kernel_name .. name_color .. 304*aedd6be5SKyle Evans choice .. color.default() 305fd2b19b3SKyle Evans return color.highlight("K") .. "ernel: " .. 306fd2b19b3SKyle Evans kernel_name .. " (" .. idx .. " of " .. 307*aedd6be5SKyle Evans #all_choices .. ")" 308088b4f5fSWarner Losh end, 3095d1e2f83SKyle Evans func = function(idx, choice, all_choices) 310*aedd6be5SKyle Evans config.selectkernel(choice) 311088b4f5fSWarner Losh end, 312088b4f5fSWarner Losh alias = {"k", "K"} 313088b4f5fSWarner Losh }, 314088b4f5fSWarner Losh 315088b4f5fSWarner Losh -- boot options 316088b4f5fSWarner Losh { 317a7cf0562SKyle Evans entry_type = core.MENU_SUBMENU, 318088b4f5fSWarner Losh name = function() 319fd2b19b3SKyle Evans return "Boot " .. color.highlight("O") .. 320*aedd6be5SKyle Evans "ptions" 321088b4f5fSWarner Losh end, 322088b4f5fSWarner Losh submenu = function() 323*aedd6be5SKyle Evans return menu.boot_options 324088b4f5fSWarner Losh end, 325088b4f5fSWarner Losh alias = {"o", "O"} 326d8757746SKyle Evans }, 327d8757746SKyle Evans }, 328*aedd6be5SKyle Evans} 329088b4f5fSWarner Losh 330088b4f5fSWarner Loshfunction menu.run(m) 331088b4f5fSWarner Losh 332088b4f5fSWarner Losh if (menu.skip()) then 333*aedd6be5SKyle Evans core.autoboot() 334*aedd6be5SKyle Evans return false 335088b4f5fSWarner Losh end 336088b4f5fSWarner Losh 337088b4f5fSWarner Losh if (m == nil) then 338*aedd6be5SKyle Evans m = menu.welcome 339088b4f5fSWarner Losh end 340088b4f5fSWarner Losh 341088b4f5fSWarner Losh -- redraw screen 342*aedd6be5SKyle Evans screen.clear() 343*aedd6be5SKyle Evans screen.defcursor() 344*aedd6be5SKyle Evans local alias_table = drawer.drawscreen(m) 345088b4f5fSWarner Losh 346*aedd6be5SKyle Evans menu.autoboot() 347088b4f5fSWarner Losh 348*aedd6be5SKyle Evans cont = true 34924a1bd54SKyle Evans while (cont) do 350*aedd6be5SKyle Evans local key = io.getchar() 351088b4f5fSWarner Losh 352b458bf0dSKyle Evans -- Special key behaviors 3531504bce3SKyle Evans if ((key == core.KEY_BACKSPACE) or (key == core.KEY_DELETE)) and 3541504bce3SKyle Evans (m ~= menu.welcome) then 355*aedd6be5SKyle Evans break 356fe672a15SKyle Evans elseif (key == core.KEY_ENTER) then 357*aedd6be5SKyle Evans core.boot() 358b458bf0dSKyle Evans -- Should not return 359abc4f7e7SKyle Evans end 360abc4f7e7SKyle Evans 361abc4f7e7SKyle Evans key = string.char(key) 362088b4f5fSWarner Losh -- check to see if key is an alias 363*aedd6be5SKyle Evans local sel_entry = nil 364088b4f5fSWarner Losh for k, v in pairs(alias_table) do 365088b4f5fSWarner Losh if (key == k) then 366*aedd6be5SKyle Evans sel_entry = v 367088b4f5fSWarner Losh end 368088b4f5fSWarner Losh end 369088b4f5fSWarner Losh 370088b4f5fSWarner Losh -- if we have an alias do the assigned action: 371088b4f5fSWarner Losh if (sel_entry ~= nil) then 3728d415029SKyle Evans -- Get menu handler 373*aedd6be5SKyle Evans local handler = menu.handlers[sel_entry.entry_type] 3748d415029SKyle Evans if (handler ~= nil) then 3758d415029SKyle Evans -- The handler's return value indicates whether 3768d415029SKyle Evans -- we need to exit this menu. An omitted return 3778d415029SKyle Evans -- value means "continue" by default. 378*aedd6be5SKyle Evans cont = handler(m, sel_entry) 3798d415029SKyle Evans if (cont == nil) then 380*aedd6be5SKyle Evans cont = true 381aefcaa7eSKyle Evans end 382088b4f5fSWarner Losh end 383088b4f5fSWarner Losh -- if we got an alias key the screen is out of date: 384*aedd6be5SKyle Evans screen.clear() 385*aedd6be5SKyle Evans screen.defcursor() 386*aedd6be5SKyle Evans alias_table = drawer.drawscreen(m) 387088b4f5fSWarner Losh end 388088b4f5fSWarner Losh end 389088b4f5fSWarner Losh 390088b4f5fSWarner Losh if (m == menu.welcome) then 391*aedd6be5SKyle Evans screen.defcursor() 392*aedd6be5SKyle Evans print("Exiting menu!") 393*aedd6be5SKyle Evans return false 394088b4f5fSWarner Losh end 395088b4f5fSWarner Losh 396*aedd6be5SKyle Evans return true 397088b4f5fSWarner Loshend 398088b4f5fSWarner Losh 399088b4f5fSWarner Loshfunction menu.skip() 400b140d14bSKyle Evans if (core.isSerialBoot()) then 401*aedd6be5SKyle Evans return true 402088b4f5fSWarner Losh end 403*aedd6be5SKyle Evans local c = string.lower(loader.getenv("console") or "") 40424a1bd54SKyle Evans if ((c:match("^efi[ ;]") or c:match("[ ;]efi[ ;]")) ~= nil) then 405*aedd6be5SKyle Evans return true 406088b4f5fSWarner Losh end 407088b4f5fSWarner Losh 408*aedd6be5SKyle Evans c = string.lower(loader.getenv("beastie_disable") or "") 409*aedd6be5SKyle Evans print("beastie_disable", c) 410*aedd6be5SKyle Evans return c == "yes" 411088b4f5fSWarner Loshend 412088b4f5fSWarner Losh 413088b4f5fSWarner Loshfunction menu.autoboot() 41424a1bd54SKyle Evans if (menu.already_autoboot == true) then 415*aedd6be5SKyle Evans return 416088b4f5fSWarner Losh end 417*aedd6be5SKyle Evans menu.already_autoboot = true 418088b4f5fSWarner Losh 419*aedd6be5SKyle Evans local ab = loader.getenv("autoboot_delay") 420702b460dSKyle Evans if (ab ~= nil) and (ab:lower() == "no") then 421*aedd6be5SKyle Evans return 422702b460dSKyle Evans elseif (tonumber(ab) == -1) then 423*aedd6be5SKyle Evans core.boot() 424088b4f5fSWarner Losh end 425*aedd6be5SKyle Evans ab = tonumber(ab) or 10 426088b4f5fSWarner Losh 427*aedd6be5SKyle Evans local x = loader.getenv("loader_menu_timeout_x") or 5 428*aedd6be5SKyle Evans local y = loader.getenv("loader_menu_timeout_y") or 22 429088b4f5fSWarner Losh 430*aedd6be5SKyle Evans local endtime = loader.time() + ab 431*aedd6be5SKyle Evans local time 432088b4f5fSWarner Losh 433088b4f5fSWarner Losh repeat 434*aedd6be5SKyle Evans time = endtime - loader.time() 435*aedd6be5SKyle Evans screen.setcursor(x, y) 43657099121SKyle Evans print("Autoboot in " .. time .. 43757099121SKyle Evans " seconds, hit [Enter] to boot" .. 438*aedd6be5SKyle Evans " or any other key to stop ") 439*aedd6be5SKyle Evans screen.defcursor() 44024a1bd54SKyle Evans if (io.ischar()) then 441*aedd6be5SKyle Evans local ch = io.getchar() 44224a1bd54SKyle Evans if (ch == core.KEY_ENTER) then 443*aedd6be5SKyle Evans break 444088b4f5fSWarner Losh else 445088b4f5fSWarner Losh -- erase autoboot msg 446*aedd6be5SKyle Evans screen.setcursor(0, y) 447088b4f5fSWarner Losh print(" " 448*aedd6be5SKyle Evans .. " ") 449*aedd6be5SKyle Evans screen.defcursor() 450*aedd6be5SKyle Evans return 451088b4f5fSWarner Losh end 452088b4f5fSWarner Losh end 453088b4f5fSWarner Losh 454*aedd6be5SKyle Evans loader.delay(50000) 455*aedd6be5SKyle Evans until time <= 0 456*aedd6be5SKyle Evans core.boot() 457088b4f5fSWarner Losh 458088b4f5fSWarner Loshend 459088b4f5fSWarner Losh 460*aedd6be5SKyle Evansreturn menu 461