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 31aedd6be5SKyle Evanslocal core = require("core") 32aedd6be5SKyle Evanslocal color = require("color") 33aedd6be5SKyle Evanslocal config = require("config") 34aedd6be5SKyle Evanslocal screen = require("screen") 35aedd6be5SKyle Evanslocal drawer = require("drawer") 36088b4f5fSWarner Losh 37aedd6be5SKyle Evanslocal menu = {} 38c8518398SKyle Evans 39aedd6be5SKyle Evanslocal skip 40aedd6be5SKyle Evanslocal run 41aedd6be5SKyle Evanslocal autoboot 42088b4f5fSWarner Losh 43e15abd1fSKyle Evanslocal OnOff = function(str, b) 449f71d421SKyle Evans if b then 45e15abd1fSKyle Evans return str .. color.escapef(color.GREEN) .. "On" .. 46aedd6be5SKyle Evans color.escapef(color.WHITE) 47e15abd1fSKyle Evans else 48e15abd1fSKyle Evans return str .. color.escapef(color.RED) .. "off" .. 49aedd6be5SKyle 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 62aedd6be5SKyle Evans entry.func() 638d415029SKyle Evans end, 648d415029SKyle Evans [core.MENU_CAROUSEL_ENTRY] = function(current_menu, entry) 658d415029SKyle Evans -- carousel (rotating) functionality 66aedd6be5SKyle Evans local carid = entry.carousel_id 67aedd6be5SKyle Evans local caridx = config.getCarouselIndex(carid) 68aedd6be5SKyle Evans local choices = entry.items() 698d415029SKyle Evans 709f71d421SKyle Evans if #choices > 0 then 71aedd6be5SKyle Evans caridx = (caridx % #choices) + 1 72aedd6be5SKyle Evans config.setCarouselIndex(carid, caridx) 73aedd6be5SKyle 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*9a28f948SKyle 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 829f71d421SKyle Evans if entry.func ~= nil then 83aedd6be5SKyle Evans entry.func() 848d415029SKyle Evans end 85aedd6be5SKyle Evans return false 868d415029SKyle Evans end, 87aedd6be5SKyle 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" .. 97aedd6be5SKyle 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") .. 106aedd6be5SKyle Evans "efaults" 107088b4f5fSWarner Losh end, 108088b4f5fSWarner Losh func = function() 109aedd6be5SKyle 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 }, 117088b4f5fSWarner Losh 118088b4f5fSWarner Losh { 119a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 120088b4f5fSWarner Losh name = function() 121aedd6be5SKyle Evans return "Boot Options:" 122088b4f5fSWarner Losh end 123088b4f5fSWarner Losh }, 124088b4f5fSWarner Losh 125088b4f5fSWarner Losh -- acpi 126088b4f5fSWarner Losh { 127a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 128c1ab36f5SKyle Evans visible = core.isSystem386, 129088b4f5fSWarner Losh name = function() 130fd2b19b3SKyle Evans return OnOff(color.highlight("A") .. 131aedd6be5SKyle Evans "CPI :", core.acpi) 132088b4f5fSWarner Losh end, 133088b4f5fSWarner Losh func = function() 134aedd6be5SKyle Evans core.setACPI() 135088b4f5fSWarner Losh end, 136088b4f5fSWarner Losh alias = {"a", "A"} 137088b4f5fSWarner Losh }, 138088b4f5fSWarner Losh -- safe mode 139088b4f5fSWarner Losh { 140a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 141088b4f5fSWarner Losh name = function() 14257099121SKyle Evans return OnOff("Safe " .. color.highlight("M") .. 143aedd6be5SKyle Evans "ode :", core.sm) 144088b4f5fSWarner Losh end, 145088b4f5fSWarner Losh func = function() 146aedd6be5SKyle Evans core.setSafeMode() 147088b4f5fSWarner Losh end, 148088b4f5fSWarner Losh alias = {"m", "M"} 149088b4f5fSWarner Losh }, 150088b4f5fSWarner Losh -- single user 151088b4f5fSWarner Losh { 152a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 153088b4f5fSWarner Losh name = function() 154fd2b19b3SKyle Evans return OnOff(color.highlight("S") .. 155aedd6be5SKyle Evans "ingle user:", core.su) 156088b4f5fSWarner Losh end, 157088b4f5fSWarner Losh func = function() 158aedd6be5SKyle Evans core.setSingleUser() 159088b4f5fSWarner Losh end, 160088b4f5fSWarner Losh alias = {"s", "S"} 161088b4f5fSWarner Losh }, 162088b4f5fSWarner Losh -- verbose boot 163088b4f5fSWarner Losh { 164a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 165088b4f5fSWarner Losh name = function() 166fd2b19b3SKyle Evans return OnOff(color.highlight("V") .. 167aedd6be5SKyle Evans "erbose :", core.verbose) 168088b4f5fSWarner Losh end, 169088b4f5fSWarner Losh func = function() 170aedd6be5SKyle Evans core.setVerbose() 171088b4f5fSWarner Losh end, 172088b4f5fSWarner Losh alias = {"v", "V"} 173088b4f5fSWarner Losh }, 174d8757746SKyle Evans }, 175aedd6be5SKyle Evans} 176088b4f5fSWarner Losh 177088b4f5fSWarner Loshmenu.welcome = { 178303253e5SKyle Evans entries = function() 179aedd6be5SKyle Evans local menu_entries = menu.welcome.all_entries 180303253e5SKyle Evans -- Swap the first two menu items on single user boot 1819f71d421SKyle Evans if core.isSingleUserBoot() then 1829a0904b0SKyle Evans -- We'll cache the swapped menu, for performance 1839f71d421SKyle Evans if menu.welcome.swapped_menu ~= nil then 184aedd6be5SKyle Evans return menu.welcome.swapped_menu 1859a0904b0SKyle Evans end 1865c1b5165SKyle Evans -- Shallow copy the table 187aedd6be5SKyle Evans menu_entries = core.shallowCopyTable(menu_entries) 1885c1b5165SKyle Evans 1899a0904b0SKyle Evans -- Swap the first two menu entries 1904b6da14cSKyle Evans menu_entries[1], menu_entries[2] = 191aedd6be5SKyle Evans menu_entries[2], menu_entries[1] 192303253e5SKyle Evans 1939a0904b0SKyle Evans -- Then set their names to their alternate names 1949a0904b0SKyle Evans menu_entries[1].name, menu_entries[2].name = 1959a0904b0SKyle Evans menu_entries[1].alternate_name, 196aedd6be5SKyle Evans menu_entries[2].alternate_name 197aedd6be5SKyle Evans menu.welcome.swapped_menu = menu_entries 198303253e5SKyle Evans end 199aedd6be5SKyle Evans return menu_entries 200303253e5SKyle Evans end, 201303253e5SKyle Evans all_entries = { 202088b4f5fSWarner Losh -- boot multi user 203088b4f5fSWarner Losh { 204a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 205088b4f5fSWarner Losh name = function() 206fd2b19b3SKyle Evans return color.highlight("B") .. 207fd2b19b3SKyle Evans "oot Multi user " .. 208aedd6be5SKyle Evans color.highlight("[Enter]") 209088b4f5fSWarner Losh end, 2105c1b5165SKyle Evans -- Not a standard menu entry function! 2115c1b5165SKyle Evans alternate_name = function() 2125c1b5165SKyle Evans return color.highlight("B") .. 213aedd6be5SKyle Evans "oot Multi user" 2145c1b5165SKyle Evans end, 215088b4f5fSWarner Losh func = function() 216aedd6be5SKyle Evans core.setSingleUser(false) 217aedd6be5SKyle Evans core.boot() 218088b4f5fSWarner Losh end, 219b458bf0dSKyle Evans alias = {"b", "B"} 220088b4f5fSWarner Losh }, 221088b4f5fSWarner Losh 222088b4f5fSWarner Losh -- boot single user 223088b4f5fSWarner Losh { 224a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 225088b4f5fSWarner Losh name = function() 226fd2b19b3SKyle Evans return "Boot " .. color.highlight("S") .. 227aedd6be5SKyle Evans "ingle user" 228088b4f5fSWarner Losh end, 2295c1b5165SKyle Evans -- Not a standard menu entry function! 2305c1b5165SKyle Evans alternate_name = function() 2315c1b5165SKyle Evans return "Boot " .. color.highlight("S") .. 232aedd6be5SKyle Evans "ingle user " .. color.highlight("[Enter]") 2335c1b5165SKyle Evans end, 234088b4f5fSWarner Losh func = function() 235aedd6be5SKyle Evans core.setSingleUser(true) 236aedd6be5SKyle Evans core.boot() 237088b4f5fSWarner Losh end, 238088b4f5fSWarner Losh alias = {"s", "S"} 239088b4f5fSWarner Losh }, 240088b4f5fSWarner Losh 241088b4f5fSWarner Losh -- escape to interpreter 242088b4f5fSWarner Losh { 243a7cf0562SKyle Evans entry_type = core.MENU_RETURN, 244088b4f5fSWarner Losh name = function() 245fd2b19b3SKyle Evans return color.highlight("Esc") .. 246aedd6be5SKyle Evans "ape to loader prompt" 247088b4f5fSWarner Losh end, 248ef625845SKyle Evans func = function() 249aedd6be5SKyle Evans loader.setenv("autoboot_delay", "NO") 250ef625845SKyle Evans end, 25139006570SKyle Evans alias = {core.KEYSTR_ESCAPE} 252088b4f5fSWarner Losh }, 253088b4f5fSWarner Losh 254088b4f5fSWarner Losh -- reboot 255088b4f5fSWarner Losh { 256a7cf0562SKyle Evans entry_type = core.MENU_ENTRY, 257088b4f5fSWarner Losh name = function() 258aedd6be5SKyle Evans return color.highlight("R") .. "eboot" 259088b4f5fSWarner Losh end, 260088b4f5fSWarner Losh func = function() 261aedd6be5SKyle Evans loader.perform("reboot") 262088b4f5fSWarner Losh end, 263088b4f5fSWarner Losh alias = {"r", "R"} 264088b4f5fSWarner Losh }, 265088b4f5fSWarner Losh 266088b4f5fSWarner Losh 267088b4f5fSWarner Losh { 268a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 269088b4f5fSWarner Losh }, 270088b4f5fSWarner Losh 271088b4f5fSWarner Losh { 272a7cf0562SKyle Evans entry_type = core.MENU_SEPARATOR, 273088b4f5fSWarner Losh name = function() 274aedd6be5SKyle Evans return "Options:" 275088b4f5fSWarner Losh end 276088b4f5fSWarner Losh }, 277088b4f5fSWarner Losh 278088b4f5fSWarner Losh -- kernel options 279088b4f5fSWarner Losh { 280a7cf0562SKyle Evans entry_type = core.MENU_CAROUSEL_ENTRY, 281ada26c4aSKyle Evans carousel_id = "kernel", 282ada26c4aSKyle Evans items = core.kernelList, 283ada26c4aSKyle Evans name = function(idx, choice, all_choices) 2849f71d421SKyle Evans if #all_choices == 0 then 285aedd6be5SKyle Evans return "Kernel: " 286088b4f5fSWarner Losh end 287b1b1f2b8SKyle Evans 288aedd6be5SKyle Evans local is_default = (idx == 1) 289aedd6be5SKyle Evans local kernel_name = "" 290aedd6be5SKyle Evans local name_color 2919f71d421SKyle Evans if is_default then 292aedd6be5SKyle Evans name_color = color.escapef(color.GREEN) 293aedd6be5SKyle Evans kernel_name = "default/" 294bcf48a15SKyle Evans else 295aedd6be5SKyle Evans name_color = color.escapef(color.BLUE) 296b1b1f2b8SKyle Evans end 297fd2b19b3SKyle Evans kernel_name = kernel_name .. name_color .. 298aedd6be5SKyle Evans choice .. color.default() 299fd2b19b3SKyle Evans return color.highlight("K") .. "ernel: " .. 300fd2b19b3SKyle Evans kernel_name .. " (" .. idx .. " of " .. 301aedd6be5SKyle Evans #all_choices .. ")" 302088b4f5fSWarner Losh end, 3035d1e2f83SKyle Evans func = function(idx, choice, all_choices) 304aedd6be5SKyle Evans config.selectkernel(choice) 305088b4f5fSWarner Losh end, 306088b4f5fSWarner Losh alias = {"k", "K"} 307088b4f5fSWarner Losh }, 308088b4f5fSWarner Losh 309088b4f5fSWarner Losh -- boot options 310088b4f5fSWarner Losh { 311a7cf0562SKyle Evans entry_type = core.MENU_SUBMENU, 312088b4f5fSWarner Losh name = function() 313fd2b19b3SKyle Evans return "Boot " .. color.highlight("O") .. 314aedd6be5SKyle Evans "ptions" 315088b4f5fSWarner Losh end, 316*9a28f948SKyle Evans submenu = menu.boot_options, 317088b4f5fSWarner Losh alias = {"o", "O"} 318d8757746SKyle Evans }, 319d8757746SKyle Evans }, 320aedd6be5SKyle Evans} 321088b4f5fSWarner Losh 32220a81676SKyle Evansmenu.default = menu.welcome 32320a81676SKyle Evans 324088b4f5fSWarner Loshfunction menu.run(m) 325088b4f5fSWarner Losh 3269f71d421SKyle Evans if menu.skip() then 327aedd6be5SKyle Evans core.autoboot() 328aedd6be5SKyle Evans return false 329088b4f5fSWarner Losh end 330088b4f5fSWarner Losh 3319f71d421SKyle Evans if m == nil then 33220a81676SKyle Evans m = menu.default 333088b4f5fSWarner Losh end 334088b4f5fSWarner Losh 335088b4f5fSWarner Losh -- redraw screen 336aedd6be5SKyle Evans screen.clear() 337aedd6be5SKyle Evans screen.defcursor() 338aedd6be5SKyle Evans local alias_table = drawer.drawscreen(m) 339088b4f5fSWarner Losh 340aedd6be5SKyle Evans menu.autoboot() 341088b4f5fSWarner Losh 342aedd6be5SKyle Evans cont = true 3439f71d421SKyle Evans while cont do 344aedd6be5SKyle Evans local key = io.getchar() 345088b4f5fSWarner Losh 346b458bf0dSKyle Evans -- Special key behaviors 3479f71d421SKyle Evans if (key == core.KEY_BACKSPACE or key == core.KEY_DELETE) and 34820a81676SKyle Evans m ~= menu.default then 349aedd6be5SKyle Evans break 3509f71d421SKyle Evans elseif key == core.KEY_ENTER then 351aedd6be5SKyle Evans core.boot() 352b458bf0dSKyle Evans -- Should not return 353abc4f7e7SKyle Evans end 354abc4f7e7SKyle Evans 355abc4f7e7SKyle Evans key = string.char(key) 356088b4f5fSWarner Losh -- check to see if key is an alias 357aedd6be5SKyle Evans local sel_entry = nil 358088b4f5fSWarner Losh for k, v in pairs(alias_table) do 3599f71d421SKyle Evans if key == k then 360aedd6be5SKyle Evans sel_entry = v 361088b4f5fSWarner Losh end 362088b4f5fSWarner Losh end 363088b4f5fSWarner Losh 364088b4f5fSWarner Losh -- if we have an alias do the assigned action: 3659f71d421SKyle Evans if sel_entry ~= nil then 3668d415029SKyle Evans -- Get menu handler 367aedd6be5SKyle Evans local handler = menu.handlers[sel_entry.entry_type] 3689f71d421SKyle Evans if handler ~= nil then 3698d415029SKyle Evans -- The handler's return value indicates whether 3708d415029SKyle Evans -- we need to exit this menu. An omitted return 3718d415029SKyle Evans -- value means "continue" by default. 372aedd6be5SKyle Evans cont = handler(m, sel_entry) 3739f71d421SKyle Evans if cont == nil then 374aedd6be5SKyle Evans cont = true 375aefcaa7eSKyle Evans end 376088b4f5fSWarner Losh end 377088b4f5fSWarner Losh -- if we got an alias key the screen is out of date: 378aedd6be5SKyle Evans screen.clear() 379aedd6be5SKyle Evans screen.defcursor() 380aedd6be5SKyle Evans alias_table = drawer.drawscreen(m) 381088b4f5fSWarner Losh end 382088b4f5fSWarner Losh end 383088b4f5fSWarner Losh 38420a81676SKyle Evans if m == menu.default then 385aedd6be5SKyle Evans screen.defcursor() 386aedd6be5SKyle Evans print("Exiting menu!") 387aedd6be5SKyle Evans return false 388088b4f5fSWarner Losh end 389088b4f5fSWarner Losh 390aedd6be5SKyle Evans return true 391088b4f5fSWarner Loshend 392088b4f5fSWarner Losh 393088b4f5fSWarner Loshfunction menu.skip() 3949f71d421SKyle Evans if core.isSerialBoot() then 395aedd6be5SKyle Evans return true 396088b4f5fSWarner Losh end 397aedd6be5SKyle Evans local c = string.lower(loader.getenv("console") or "") 3989f71d421SKyle Evans if c:match("^efi[ ;]") ~= nil or c:match("[ ;]efi[ ;]") ~= nil then 399aedd6be5SKyle Evans return true 400088b4f5fSWarner Losh end 401088b4f5fSWarner Losh 402aedd6be5SKyle Evans c = string.lower(loader.getenv("beastie_disable") or "") 403aedd6be5SKyle Evans print("beastie_disable", c) 404aedd6be5SKyle Evans return c == "yes" 405088b4f5fSWarner Loshend 406088b4f5fSWarner Losh 407088b4f5fSWarner Loshfunction menu.autoboot() 40849550489SKyle Evans if menu.already_autoboot then 409aedd6be5SKyle Evans return 410088b4f5fSWarner Losh end 411aedd6be5SKyle Evans menu.already_autoboot = true 412088b4f5fSWarner Losh 413aedd6be5SKyle Evans local ab = loader.getenv("autoboot_delay") 4149f71d421SKyle Evans if ab ~= nil and ab:lower() == "no" then 415aedd6be5SKyle Evans return 4169f71d421SKyle Evans elseif tonumber(ab) == -1 then 417aedd6be5SKyle Evans core.boot() 418088b4f5fSWarner Losh end 419aedd6be5SKyle Evans ab = tonumber(ab) or 10 420088b4f5fSWarner Losh 421aedd6be5SKyle Evans local x = loader.getenv("loader_menu_timeout_x") or 5 422aedd6be5SKyle Evans local y = loader.getenv("loader_menu_timeout_y") or 22 423088b4f5fSWarner Losh 424aedd6be5SKyle Evans local endtime = loader.time() + ab 425aedd6be5SKyle Evans local time 426088b4f5fSWarner Losh 427088b4f5fSWarner Losh repeat 428aedd6be5SKyle Evans time = endtime - loader.time() 429aedd6be5SKyle Evans screen.setcursor(x, y) 43057099121SKyle Evans print("Autoboot in " .. time .. 43157099121SKyle Evans " seconds, hit [Enter] to boot" .. 432aedd6be5SKyle Evans " or any other key to stop ") 433aedd6be5SKyle Evans screen.defcursor() 4349f71d421SKyle Evans if io.ischar() then 435aedd6be5SKyle Evans local ch = io.getchar() 4369f71d421SKyle Evans if ch == core.KEY_ENTER then 437aedd6be5SKyle Evans break 438088b4f5fSWarner Losh else 439088b4f5fSWarner Losh -- erase autoboot msg 440aedd6be5SKyle Evans screen.setcursor(0, y) 441088b4f5fSWarner Losh print(" " 442aedd6be5SKyle Evans .. " ") 443aedd6be5SKyle Evans screen.defcursor() 444aedd6be5SKyle Evans return 445088b4f5fSWarner Losh end 446088b4f5fSWarner Losh end 447088b4f5fSWarner Losh 448aedd6be5SKyle Evans loader.delay(50000) 449aedd6be5SKyle Evans until time <= 0 450aedd6be5SKyle Evans core.boot() 451088b4f5fSWarner Losh 452088b4f5fSWarner Loshend 453088b4f5fSWarner Losh 454aedd6be5SKyle Evansreturn menu 455