xref: /freebsd-src/stand/lua/cli.lua (revision b38a82c77ab90eace53c56151b191efd1f4a8439)
1e37f4622SKyle Evans--
24d846d26SWarner Losh-- SPDX-License-Identifier: BSD-2-Clause
372e39d71SKyle Evans--
4e37f4622SKyle Evans-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
5e37f4622SKyle Evans--
6e37f4622SKyle Evans-- Redistribution and use in source and binary forms, with or without
7e37f4622SKyle Evans-- modification, are permitted provided that the following conditions
8e37f4622SKyle Evans-- are met:
9e37f4622SKyle Evans-- 1. Redistributions of source code must retain the above copyright
10e37f4622SKyle Evans--    notice, this list of conditions and the following disclaimer.
11e37f4622SKyle Evans-- 2. Redistributions in binary form must reproduce the above copyright
12e37f4622SKyle Evans--    notice, this list of conditions and the following disclaimer in the
13e37f4622SKyle Evans--    documentation and/or other materials provided with the distribution.
14e37f4622SKyle Evans--
15e37f4622SKyle Evans-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e37f4622SKyle Evans-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e37f4622SKyle Evans-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e37f4622SKyle Evans-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e37f4622SKyle Evans-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e37f4622SKyle Evans-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e37f4622SKyle Evans-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e37f4622SKyle Evans-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e37f4622SKyle Evans-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e37f4622SKyle Evans-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e37f4622SKyle Evans-- SUCH DAMAGE.
26e37f4622SKyle Evans--
27e37f4622SKyle Evans
283e6c7d54SKyle Evanslocal config = require("config")
293e6c7d54SKyle Evanslocal core = require("core")
30e37f4622SKyle Evans
31e37f4622SKyle Evanslocal cli = {}
32e37f4622SKyle Evans
33*b38a82c7SWarner Loshif not pager then
34*b38a82c7SWarner Losh	-- shim for the pager module that just doesn't do it.
35*b38a82c7SWarner Losh	-- XXX Remove after 12.2 goes EoL.
36*b38a82c7SWarner Losh	pager = {
37*b38a82c7SWarner Losh		open = function() end,
38*b38a82c7SWarner Losh		close = function() end,
39*b38a82c7SWarner Losh		output = function(str)
40*b38a82c7SWarner Losh			printc(str)
41*b38a82c7SWarner Losh		end,
42*b38a82c7SWarner Losh	}
43*b38a82c7SWarner Loshend
44*b38a82c7SWarner Losh
45e37f4622SKyle Evans-- Internal function
46e37f4622SKyle Evans-- Parses arguments to boot and returns two values: kernel_name, argstr
47e37f4622SKyle Evans-- Defaults to nil and "" respectively.
48e37f4622SKyle Evans-- This will also parse arguments to autoboot, but the with_kernel argument
49e37f4622SKyle Evans-- will need to be explicitly overwritten to false
50322a2dddSKyle Evanslocal function parseBootArgs(argv, with_kernel)
51e37f4622SKyle Evans	if with_kernel == nil then
52e37f4622SKyle Evans		with_kernel = true
53e37f4622SKyle Evans	end
54e37f4622SKyle Evans	if #argv == 0 then
55e37f4622SKyle Evans		if with_kernel then
56e37f4622SKyle Evans			return nil, ""
57e37f4622SKyle Evans		else
58e37f4622SKyle Evans			return ""
59e37f4622SKyle Evans		end
60e37f4622SKyle Evans	end
61e37f4622SKyle Evans	local kernel_name
62e37f4622SKyle Evans	local argstr = ""
63e37f4622SKyle Evans
64e2df27e3SKyle Evans	for _, v in ipairs(argv) do
65e37f4622SKyle Evans		if with_kernel and v:sub(1,1) ~= "-" then
66e37f4622SKyle Evans			kernel_name = v
67e37f4622SKyle Evans		else
68e37f4622SKyle Evans			argstr = argstr .. " " .. v
69e37f4622SKyle Evans		end
70e37f4622SKyle Evans	end
71e37f4622SKyle Evans	if with_kernel then
72e37f4622SKyle Evans		return kernel_name, argstr
73e37f4622SKyle Evans	else
74e37f4622SKyle Evans		return argstr
75e37f4622SKyle Evans	end
76e37f4622SKyle Evansend
77e37f4622SKyle Evans
784634bb1fSKyle Evanslocal function setModule(module, loading)
794634bb1fSKyle Evans	if loading and config.enableModule(module) then
804634bb1fSKyle Evans		print(module .. " will be loaded")
814634bb1fSKyle Evans	elseif not loading and config.disableModule(module) then
824634bb1fSKyle Evans		print(module .. " will not be loaded")
834634bb1fSKyle Evans	end
844634bb1fSKyle Evansend
854634bb1fSKyle Evans
86e37f4622SKyle Evans-- Declares a global function cli_execute that attempts to dispatch the
87e37f4622SKyle Evans-- arguments passed as a lua function. This gives lua a chance to intercept
88e37f4622SKyle Evans-- builtin CLI commands like "boot"
8922ae8ae1SKyle Evans-- This function intentionally does not follow our general naming guideline for
9022ae8ae1SKyle Evans-- functions. This is global pollution, but the clearly separated 'cli' looks
9122ae8ae1SKyle Evans-- more like a module indicator to serve as a hint of where to look for the
9222ae8ae1SKyle Evans-- corresponding definition.
93e37f4622SKyle Evansfunction cli_execute(...)
94e37f4622SKyle Evans	local argv = {...}
95e37f4622SKyle Evans	-- Just in case...
96e37f4622SKyle Evans	if #argv == 0 then
97c6d9f133SKyle Evans		return loader.command(...)
98e37f4622SKyle Evans	end
99e37f4622SKyle Evans
100e37f4622SKyle Evans	local cmd_name = argv[1]
1012e4dad82SKyle Evans	local cmd = cli[cmd_name]
102e37f4622SKyle Evans	if cmd ~= nil and type(cmd) == "function" then
103e37f4622SKyle Evans		-- Pass argv wholesale into cmd. We could omit argv[0] since the
104e37f4622SKyle Evans		-- traditional reasons for including it don't necessarily apply,
105e37f4622SKyle Evans		-- it may not be totally redundant if we want to have one global
106e37f4622SKyle Evans		-- handling multiple commands
107c6d9f133SKyle Evans		return cmd(...)
108e37f4622SKyle Evans	else
109c6d9f133SKyle Evans		return loader.command(...)
110e37f4622SKyle Evans	end
111e37f4622SKyle Evans
112e37f4622SKyle Evansend
113e37f4622SKyle Evans
114ca3b8c9fSKyle Evansfunction cli_execute_unparsed(str)
115f6e00525SKyle Evans	return cli_execute(loader.parse(str))
116697f127dSKyle Evansend
117697f127dSKyle Evans
118eca5ca66SKyle Evans-- Module exports
119eca5ca66SKyle Evans
1202e4dad82SKyle Evansfunction cli.boot(...)
121e2df27e3SKyle Evans	local _, argv = cli.arguments(...)
122322a2dddSKyle Evans	local kernel, argstr = parseBootArgs(argv)
1232e4dad82SKyle Evans	if kernel ~= nil then
1242e4dad82SKyle Evans		loader.perform("unload")
125322a2dddSKyle Evans		config.selectKernel(kernel)
1262e4dad82SKyle Evans	end
1272e4dad82SKyle Evans	core.boot(argstr)
1282e4dad82SKyle Evansend
1292e4dad82SKyle Evans
1302e4dad82SKyle Evansfunction cli.autoboot(...)
131e2df27e3SKyle Evans	local _, argv = cli.arguments(...)
132322a2dddSKyle Evans	local argstr = parseBootArgs(argv, false)
1332e4dad82SKyle Evans	core.autoboot(argstr)
1342e4dad82SKyle Evansend
1352e4dad82SKyle Evans
13683f7a74cSKyle Evanscli['boot-conf'] = function(...)
13783f7a74cSKyle Evans	local _, argv = cli.arguments(...)
13883f7a74cSKyle Evans	local kernel, argstr = parseBootArgs(argv)
13983f7a74cSKyle Evans	if kernel ~= nil then
14083f7a74cSKyle Evans		loader.perform("unload")
14183f7a74cSKyle Evans		config.selectKernel(kernel)
14283f7a74cSKyle Evans	end
14383f7a74cSKyle Evans	core.autoboot(argstr)
14483f7a74cSKyle Evansend
14583f7a74cSKyle Evans
146e40d2a04SKyle Evanscli['read-conf'] = function(...)
147e40d2a04SKyle Evans	local _, argv = cli.arguments(...)
1483fe0ac6aSKyle Evans	config.readConf(assert(core.popFrontTable(argv)))
149e40d2a04SKyle Evansend
150e40d2a04SKyle Evans
15194510c29SKyle Evanscli['reload-conf'] = function()
152af876563SKyle Evans	config.reload()
153af876563SKyle Evansend
154af876563SKyle Evans
1554634bb1fSKyle Evanscli["enable-module"] = function(...)
1564634bb1fSKyle Evans	local _, argv = cli.arguments(...)
1574634bb1fSKyle Evans	if #argv == 0 then
1584634bb1fSKyle Evans		print("usage error: enable-module module")
1594634bb1fSKyle Evans		return
1604634bb1fSKyle Evans	end
1614634bb1fSKyle Evans
1624634bb1fSKyle Evans	setModule(argv[1], true)
1634634bb1fSKyle Evansend
1644634bb1fSKyle Evans
1654634bb1fSKyle Evanscli["disable-module"] = function(...)
1664634bb1fSKyle Evans	local _, argv = cli.arguments(...)
1674634bb1fSKyle Evans	if #argv == 0 then
1684634bb1fSKyle Evans		print("usage error: disable-module module")
1694634bb1fSKyle Evans		return
1704634bb1fSKyle Evans	end
1714634bb1fSKyle Evans
1724634bb1fSKyle Evans	setModule(argv[1], false)
1734634bb1fSKyle Evansend
1744634bb1fSKyle Evans
1754634bb1fSKyle Evanscli["toggle-module"] = function(...)
1764634bb1fSKyle Evans	local _, argv = cli.arguments(...)
1774634bb1fSKyle Evans	if #argv == 0 then
1784634bb1fSKyle Evans		print("usage error: toggle-module module")
1794634bb1fSKyle Evans		return
1804634bb1fSKyle Evans	end
1814634bb1fSKyle Evans
1824634bb1fSKyle Evans	local module = argv[1]
1834634bb1fSKyle Evans	setModule(module, not config.isModuleEnabled(module))
1844634bb1fSKyle Evansend
1854634bb1fSKyle Evans
1867ed84fa1SKyle Evanscli["show-module-options"] = function()
1877ed84fa1SKyle Evans	local module_info = config.getModuleInfo()
1887ed84fa1SKyle Evans	local modules = module_info['modules']
1897ed84fa1SKyle Evans	local blacklist = module_info['blacklist']
1907ed84fa1SKyle Evans	local lines = {}
1917ed84fa1SKyle Evans
1927ed84fa1SKyle Evans	for module, info in pairs(modules) do
1937ed84fa1SKyle Evans		if #lines > 0 then
1947ed84fa1SKyle Evans			lines[#lines + 1] = ""
1957ed84fa1SKyle Evans		end
1967ed84fa1SKyle Evans
1977ed84fa1SKyle Evans		lines[#lines + 1] = "Name:        " .. module
1987ed84fa1SKyle Evans		if info.name then
1997ed84fa1SKyle Evans			lines[#lines + 1] = "Path:        " .. info.name
2007ed84fa1SKyle Evans		end
2017ed84fa1SKyle Evans
2027ed84fa1SKyle Evans		if info.type then
2037ed84fa1SKyle Evans			lines[#lines + 1] = "Type:        " .. info.type
2047ed84fa1SKyle Evans		end
2057ed84fa1SKyle Evans
2067ed84fa1SKyle Evans		if info.flags then
2077ed84fa1SKyle Evans			lines[#lines + 1] = "Flags:       " .. info.flags
2087ed84fa1SKyle Evans		end
2097ed84fa1SKyle Evans
2107ed84fa1SKyle Evans		if info.before then
2117ed84fa1SKyle Evans			lines[#lines + 1] = "Before load: " .. info.before
2127ed84fa1SKyle Evans		end
2137ed84fa1SKyle Evans
2147ed84fa1SKyle Evans		if info.after then
2157ed84fa1SKyle Evans			lines[#lines + 1] = "After load:  " .. info.after
2167ed84fa1SKyle Evans		end
2177ed84fa1SKyle Evans
2187ed84fa1SKyle Evans		if info.error then
2197ed84fa1SKyle Evans			lines[#lines + 1] = "Error:       " .. info.error
2207ed84fa1SKyle Evans		end
2217ed84fa1SKyle Evans
2227ed84fa1SKyle Evans		local status
2237ed84fa1SKyle Evans		if blacklist[module] and not info.force then
2247ed84fa1SKyle Evans			status = "Blacklisted"
2257ed84fa1SKyle Evans		elseif info.load == "YES" then
2267ed84fa1SKyle Evans			status = "Load"
2277ed84fa1SKyle Evans		else
2287ed84fa1SKyle Evans			status = "Don't load"
2297ed84fa1SKyle Evans		end
2307ed84fa1SKyle Evans
2317ed84fa1SKyle Evans		lines[#lines + 1] = "Status:      " .. status
2327ed84fa1SKyle Evans	end
2337ed84fa1SKyle Evans
2347ed84fa1SKyle Evans	pager.open()
23529842cb3SKyle Evans	for _, v in ipairs(lines) do
2367ed84fa1SKyle Evans		pager.output(v .. "\n")
2377ed84fa1SKyle Evans	end
2387ed84fa1SKyle Evans	pager.close()
2397ed84fa1SKyle Evansend
2407ed84fa1SKyle Evans
24107c4b78dSWarner Loshcli["disable-device"] = function(...)
24207c4b78dSWarner Losh	local _, argv = cli.arguments(...)
24307c4b78dSWarner Losh	local d, u
24407c4b78dSWarner Losh
24507c4b78dSWarner Losh	if #argv == 0 then
24607c4b78dSWarner Losh		print("usage error: disable-device device")
24707c4b78dSWarner Losh		return
24807c4b78dSWarner Losh	end
24907c4b78dSWarner Losh
25007c4b78dSWarner Losh	d, u = string.match(argv[1], "(%w*%a)(%d+)")
25107c4b78dSWarner Losh	if d ~= nil then
25207c4b78dSWarner Losh		loader.setenv("hint." .. d .. "." .. u .. ".disabled", "1")
25307c4b78dSWarner Losh	end
25407c4b78dSWarner Loshend
25507c4b78dSWarner Losh
2562e4dad82SKyle Evans-- Used for splitting cli varargs into cmd_name and the rest of argv
257eca5ca66SKyle Evansfunction cli.arguments(...)
258eca5ca66SKyle Evans	local argv = {...}
259e2df27e3SKyle Evans	local cmd_name
260eca5ca66SKyle Evans	cmd_name, argv = core.popFrontTable(argv)
261eca5ca66SKyle Evans	return cmd_name, argv
262eca5ca66SKyle Evansend
263eca5ca66SKyle Evans
264e37f4622SKyle Evansreturn cli
265