diff --git a/usr.sbin/bsdinstall/scripts/pkgbase.in b/usr.sbin/bsdinstall/scripts/pkgbase.in --- a/usr.sbin/bsdinstall/scripts/pkgbase.in +++ b/usr.sbin/bsdinstall/scripts/pkgbase.in @@ -7,6 +7,9 @@ -- This software was developed by Isaac Freund -- under sponsorship from the FreeBSD Foundation. +local sys_wait = require("posix.sys.wait") +local unistd = require("posix.unistd") + local all_libcompats = "%%_ALL_libcompats%%" -- Run a command using the OS shell and capture the stdout @@ -38,20 +41,48 @@ end end +local function read_all(fd) + local ret = "" + repeat + local buffer = assert(unistd.read(fd, 1024)) + ret = ret .. buffer + until buffer == "" + return ret +end + +local function bsddialog(args) + local r, w = assert(unistd.pipe()) + + local pid = assert(unistd.fork()) + if pid == 0 then + assert(unistd.close(r)) + assert(unistd.dup2(w, 2)) + assert(unistd.execp("bsddialog", args)) + unistd._exit() + end + assert(unistd.close(w)) + + local output = read_all(r) + assert(unistd.close(r)) + + local _, _, exit_code = assert(sys_wait.wait(pid)) + return exit_code, output +end + -- Returns a list of pkgbase packages equivalent to the default base.txz and kernel.txz local function select_packages(pkg, options) local components = { - ["kernel"] = {}, - ["kernel-dbg"] = {}, - ["base"] = {}, - ["base-dbg"] = {}, - ["src"] = {}, - ["tests"] = {}, + kernel = {}, + kernel_dbg = {}, + base = {}, + base_dbg = {}, + src = {}, + tests = {}, } for compat in all_libcompats:gmatch("%S+") do components["lib" .. compat] = {} - components["lib" .. compat .. "-dbg"] = {} + components["lib" .. compat .. "_dbg"] = {} end local rquery = capture(pkg .. "rquery -U -r FreeBSD-base %n") @@ -65,15 +96,15 @@ if package == "FreeBSD-kernel-generic" then table.insert(components["kernel"], package) elseif package == "FreeBSD-kernel-generic-dbg" then - table.insert(components["kernel-dbg"], package) + table.insert(components["kernel_dbg"], package) end elseif package:match(".*%-dbg$") then - table.insert(components["base-dbg"], package) + table.insert(components["base_dbg"], package) else local found = false for compat in all_libcompats:gmatch("%S+") do if package:match(".*%-dbg%-lib" .. compat .. "$") then - table.insert(components["lib" .. compat .. "-dbg"], package) + table.insert(components["lib" .. compat .. "_dbg"], package) found = true break elseif package:match(".*%-lib" .. compat .. "$") then @@ -93,13 +124,70 @@ assert(#components["kernel"] == 1) assert(#components["base"] > 0) - local selected = {} - append_list(selected, components["base"]) + local descriptions = { + kernel_dbg = "Kernel (Debugging)", + base_dbg = "Base system (Debugging)", + src = "System source tree", + tests = "Test suite", + lib32 = "32-bit compatibility libraries", + lib32_dbg = "32-bit compatibility libraries (Debugging)", + } + local defaults = { + kernel_dbg = "on", + base_dbg = "off", + src = "off", + tests = "off", + lib32 = "on", + lib32_dbg = "off", + } + + local sorted_components = {} + for component, _ in pairs(components) do + table.insert(sorted_components, component) + end + table.sort(sorted_components) + + local checklist_items = {} + for _, component in ipairs(sorted_components) do + if component ~= "base" and component ~= "kernel" and + not (component == "kernel_dbg" and options.no_kernel) then + local description = descriptions[component] or "''" + local default = defaults[component] or "off" + table.insert(checklist_items, component) + table.insert(checklist_items, description) + table.insert(checklist_items, default) + end + end + + local bsddialog_args = { + "--backtitle", "FreeBSD Installer", + "--title", "Select System Components", + "--nocancel", + "--disable-esc", + "--separate-output", + "--checklist", "Choose optional system components to install:", + "0", "0", "0", -- autosize + } + append_list(bsddialog_args, checklist_items) + + local exit_code, selected_components = bsddialog(bsddialog_args) + -- This should only be possible if bsddialog is killed by a signal + -- or buggy, we disable the cancel option and esc key. + -- If this does happen, there's not much we can do except exit with a + -- hopefully useful stack trace. + assert(exit_code == 0) + + local selected_packages = {} + append_list(selected_packages, components["base"]) if not options.no_kernel then - append_list(selected, components["kernel"]) + append_list(selected_packages, components["kernel"]) + end + + for component in selected_components:gmatch("[^\n]+") do + append_list(selected_packages, components[component]) end - return selected + return selected_packages end local function parse_options()