Index: stand/lua/core.lua =================================================================== --- stand/lua/core.lua +++ stand/lua/core.lua @@ -174,6 +174,41 @@ return kernels; end +function core.bootenvDefault() + return loader.getenv("zfs_be_active"); +end + +function core.bootenvList() + local bootenv_count = tonumber(loader.getenv("bootenvs_count")); + local bootenvs = {}; + local curenv; + local curenv_idx = 0; + local envcount = 0; + local unique = {}; + + if (bootenv_count == nil) or (bootenv_count <= 0) then + return bootenvs; + end + + -- Currently selected bootenv is always first/default + curenv = core.bootenvDefault(); + if (curenv ~= nil) then + envcount = envcount + 1; + bootenvs[envcount] = curenv; + unique[curenv] = true; + end + + for curenv_idx = 0, bootenv_count - 1 do + curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]"); + if (curenv ~= nil) and (unique[curenv] == nil) then + envcount = envcount + 1; + bootenvs[envcount] = curenv; + unique[curenv] = true; + end + end + return bootenvs; +end + function core.setDefaults() core.setACPI(core.getACPIPresent(true)); core.setSafeMode(false); @@ -196,6 +231,15 @@ return single_user ~= nil and single_user:lower() == "yes"; end +function core.isZFSBoot() + local c = loader.getenv("currdev"); + + if (c ~= nil) then + return (c:match("^zfs:") ~= nil); + end + return false; +end + function core.isSerialBoot() local c = loader.getenv("console"); Index: stand/lua/menu.lua =================================================================== --- stand/lua/menu.lua +++ stand/lua/menu.lua @@ -44,6 +44,67 @@ -- loader menu tree is rooted at menu.welcome +function bootenvSet(env) + loader.setenv("vfs.root.mountfrom", env); + loader.setenv("currdev", env .. ":"); + config.reload(); +end + +menu.boot_environments = { + entries = { + -- return to welcome menu + { + entry_type = core.MENU_RETURN, + name = function() + return "Back to main menu" .. + color.highlight(" [Backspace]"); + end + }, + { + entry_type = core.MENU_CAROUSEL_ENTRY, + carousel_id = "be_active", + items = core.bootenvList, + name = function(idx, choice, all_choices) + if (#all_choices == 0) then + return "Active: "; + end + + local is_default = (idx == 1); + local bootenv_name = ""; + local name_color; + if (is_default) then + name_color = color.escapef(color.GREEN); + bootenv_name = "default/"; + else + name_color = color.escapef(color.BLUE); + end + bootenv_name = bootenv_name .. name_color .. + choice .. color.default(); + return color.highlight("A").."ctive: " .. + bootenv_name .. " (" .. idx .. " of " .. + #all_choices .. ")"; + end, + func = function(idx, choice, all_choices) + bootenvSet(choice); + end, + alias = {"a", "A"} + }, + { + entry_type = core.MENU_ENTRY, + name = function() + return color.highlight("b") .. "ootfs: " .. + core.bootenvDefault(); + end, + func = function() + -- Reset active boot environment to the default + menu.setCarouselIndex("be_active", 1); + bootenvSet(core.bootenvDefault()); + end, + alias = {"b", "B"} + }, + }, +}; + menu.boot_options = { entries = { -- return to welcome menu @@ -280,6 +341,20 @@ end, alias = {"o", "O"} }, + -- boot environments + { + entry_type = core.MENU_SUBMENU, + visible = function() + return core.isZFSBoot() and #core.bootenvList() > 1; + end, + name = function() + return "Boot " .. color.highlight("E") .. "nvironments"; + end, + submenu = function() + return menu.boot_environments; + end, + alias = {"e", "E"} + }, }, };