xref: /freebsd-13.1/stand/lua/cli.lua (revision 25b4b24e)
1e37f4622SKyle Evans--
272e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
372e39d71SKyle Evans--
4e37f4622SKyle Evans-- Copyright (c) 2018 Kyle Evans <[email protected]>
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-- $FreeBSD$
28e37f4622SKyle Evans--
29e37f4622SKyle Evans
303e6c7d54SKyle Evanslocal config = require("config")
313e6c7d54SKyle Evanslocal core = require("core")
32e37f4622SKyle Evans
33e37f4622SKyle Evanslocal cli = {}
34e37f4622SKyle Evans
357ed84fa1SKyle Evansif not pager then
367ed84fa1SKyle Evans	-- shim for the pager module that just doesn't do it.
377ed84fa1SKyle Evans	-- XXX Remove after 12.2 goes EoL.
387ed84fa1SKyle Evans	pager = {
397ed84fa1SKyle Evans		open = function() end,
407ed84fa1SKyle Evans		close = function() end,
417ed84fa1SKyle Evans		output = function(str)
427ed84fa1SKyle Evans			printc(str)
437ed84fa1SKyle Evans		end,
447ed84fa1SKyle Evans	}
457ed84fa1SKyle Evansend
467ed84fa1SKyle Evans
47e37f4622SKyle Evans-- Internal function
48e37f4622SKyle Evans-- Parses arguments to boot and returns two values: kernel_name, argstr
49e37f4622SKyle Evans-- Defaults to nil and "" respectively.
50e37f4622SKyle Evans-- This will also parse arguments to autoboot, but the with_kernel argument
51e37f4622SKyle Evans-- will need to be explicitly overwritten to false
52322a2dddSKyle Evanslocal function parseBootArgs(argv, with_kernel)
53e37f4622SKyle Evans	if with_kernel == nil then
54e37f4622SKyle Evans		with_kernel = true
55e37f4622SKyle Evans	end
56e37f4622SKyle Evans	if #argv == 0 then
57e37f4622SKyle Evans		if with_kernel then
58e37f4622SKyle Evans			return nil, ""
59e37f4622SKyle Evans		else
60e37f4622SKyle Evans			return ""
61e37f4622SKyle Evans		end
62e37f4622SKyle Evans	end
63e37f4622SKyle Evans	local kernel_name
64e37f4622SKyle Evans	local argstr = ""
65e37f4622SKyle Evans
66e2df27e3SKyle Evans	for _, v in ipairs(argv) do
67e37f4622SKyle Evans		if with_kernel and v:sub(1,1) ~= "-" then
68e37f4622SKyle Evans			kernel_name = v
69e37f4622SKyle Evans		else
70e37f4622SKyle Evans			argstr = argstr .. " " .. v
71e37f4622SKyle Evans		end
72e37f4622SKyle Evans	end
73e37f4622SKyle Evans	if with_kernel then
74e37f4622SKyle Evans		return kernel_name, argstr
75e37f4622SKyle Evans	else
76e37f4622SKyle Evans		return argstr
77e37f4622SKyle Evans	end
78e37f4622SKyle Evansend
79e37f4622SKyle Evans
804634bb1fSKyle Evanslocal function setModule(module, loading)
814634bb1fSKyle Evans	if loading and config.enableModule(module) then
824634bb1fSKyle Evans		print(module .. " will be loaded")
834634bb1fSKyle Evans	elseif not loading and config.disableModule(module) then
844634bb1fSKyle Evans		print(module .. " will not be loaded")
854634bb1fSKyle Evans	end
864634bb1fSKyle Evansend
874634bb1fSKyle Evans
88e37f4622SKyle Evans-- Declares a global function cli_execute that attempts to dispatch the
89e37f4622SKyle Evans-- arguments passed as a lua function. This gives lua a chance to intercept
90e37f4622SKyle Evans-- builtin CLI commands like "boot"
9122ae8ae1SKyle Evans-- This function intentionally does not follow our general naming guideline for
9222ae8ae1SKyle Evans-- functions. This is global pollution, but the clearly separated 'cli' looks
9322ae8ae1SKyle Evans-- more like a module indicator to serve as a hint of where to look for the
9422ae8ae1SKyle Evans-- corresponding definition.
95e37f4622SKyle Evansfunction cli_execute(...)
96e37f4622SKyle Evans	local argv = {...}
97e37f4622SKyle Evans	-- Just in case...
98e37f4622SKyle Evans	if #argv == 0 then
99c6d9f133SKyle Evans		return loader.command(...)
100e37f4622SKyle Evans	end
101e37f4622SKyle Evans
102e37f4622SKyle Evans	local cmd_name = argv[1]
1032e4dad82SKyle Evans	local cmd = cli[cmd_name]
104e37f4622SKyle Evans	if cmd ~= nil and type(cmd) == "function" then
105e37f4622SKyle Evans		-- Pass argv wholesale into cmd. We could omit argv[0] since the
106e37f4622SKyle Evans		-- traditional reasons for including it don't necessarily apply,
107e37f4622SKyle Evans		-- it may not be totally redundant if we want to have one global
108e37f4622SKyle Evans		-- handling multiple commands
109c6d9f133SKyle Evans		return cmd(...)
110e37f4622SKyle Evans	else
111c6d9f133SKyle Evans		return loader.command(...)
112e37f4622SKyle Evans	end
113e37f4622SKyle Evans
114e37f4622SKyle Evansend
115e37f4622SKyle Evans
116ca3b8c9fSKyle Evansfunction cli_execute_unparsed(str)
117f6e00525SKyle Evans	return cli_execute(loader.parse(str))
118697f127dSKyle Evansend
119697f127dSKyle Evans
120eca5ca66SKyle Evans-- Module exports
121eca5ca66SKyle Evans
1222e4dad82SKyle Evansfunction cli.boot(...)
123e2df27e3SKyle Evans	local _, argv = cli.arguments(...)
124322a2dddSKyle Evans	local kernel, argstr = parseBootArgs(argv)
1252e4dad82SKyle Evans	if kernel ~= nil then
1262e4dad82SKyle Evans		loader.perform("unload")
127322a2dddSKyle Evans		config.selectKernel(kernel)
1282e4dad82SKyle Evans	end
1292e4dad82SKyle Evans	core.boot(argstr)
1302e4dad82SKyle Evansend
1312e4dad82SKyle Evans
1322e4dad82SKyle Evansfunction cli.autoboot(...)
133e2df27e3SKyle Evans	local _, argv = cli.arguments(...)
134322a2dddSKyle Evans	local argstr = parseBootArgs(argv, false)
1352e4dad82SKyle Evans	core.autoboot(argstr)
1362e4dad82SKyle Evansend
1372e4dad82SKyle Evans
13883f7a74cSKyle Evanscli['boot-conf'] = function(...)
13983f7a74cSKyle Evans	local _, argv = cli.arguments(...)
14083f7a74cSKyle Evans	local kernel, argstr = parseBootArgs(argv)
14183f7a74cSKyle Evans	if kernel ~= nil then
14283f7a74cSKyle Evans		loader.perform("unload")
14383f7a74cSKyle Evans		config.selectKernel(kernel)
14483f7a74cSKyle Evans	end
14583f7a74cSKyle Evans	core.autoboot(argstr)
14683f7a74cSKyle Evansend
14783f7a74cSKyle Evans
148e40d2a04SKyle Evanscli['read-conf'] = function(...)
149e40d2a04SKyle Evans	local _, argv = cli.arguments(...)
1503fe0ac6aSKyle Evans	config.readConf(assert(core.popFrontTable(argv)))
151e40d2a04SKyle Evansend
152e40d2a04SKyle Evans
15394510c29SKyle Evanscli['reload-conf'] = function()
154af876563SKyle Evans	config.reload()
155af876563SKyle Evansend
156af876563SKyle Evans
1574634bb1fSKyle Evanscli["enable-module"] = function(...)
1584634bb1fSKyle Evans	local _, argv = cli.arguments(...)
1594634bb1fSKyle Evans	if #argv == 0 then
1604634bb1fSKyle Evans		print("usage error: enable-module module")
1614634bb1fSKyle Evans		return
1624634bb1fSKyle Evans	end
1634634bb1fSKyle Evans
1644634bb1fSKyle Evans	setModule(argv[1], true)
1654634bb1fSKyle Evansend
1664634bb1fSKyle Evans
1674634bb1fSKyle Evanscli["disable-module"] = function(...)
1684634bb1fSKyle Evans	local _, argv = cli.arguments(...)
1694634bb1fSKyle Evans	if #argv == 0 then
1704634bb1fSKyle Evans		print("usage error: disable-module module")
1714634bb1fSKyle Evans		return
1724634bb1fSKyle Evans	end
1734634bb1fSKyle Evans
1744634bb1fSKyle Evans	setModule(argv[1], false)
1754634bb1fSKyle Evansend
1764634bb1fSKyle Evans
1774634bb1fSKyle Evanscli["toggle-module"] = function(...)
1784634bb1fSKyle Evans	local _, argv = cli.arguments(...)
1794634bb1fSKyle Evans	if #argv == 0 then
1804634bb1fSKyle Evans		print("usage error: toggle-module module")
1814634bb1fSKyle Evans		return
1824634bb1fSKyle Evans	end
1834634bb1fSKyle Evans
1844634bb1fSKyle Evans	local module = argv[1]
1854634bb1fSKyle Evans	setModule(module, not config.isModuleEnabled(module))
1864634bb1fSKyle Evansend
1874634bb1fSKyle Evans
1887ed84fa1SKyle Evanscli["show-module-options"] = function()
1897ed84fa1SKyle Evans	local module_info = config.getModuleInfo()
1907ed84fa1SKyle Evans	local modules = module_info['modules']
1917ed84fa1SKyle Evans	local blacklist = module_info['blacklist']
1927ed84fa1SKyle Evans	local lines = {}
1937ed84fa1SKyle Evans
1947ed84fa1SKyle Evans	for module, info in pairs(modules) do
1957ed84fa1SKyle Evans		if #lines > 0 then
1967ed84fa1SKyle Evans			lines[#lines + 1] = ""
1977ed84fa1SKyle Evans		end
1987ed84fa1SKyle Evans
1997ed84fa1SKyle Evans		lines[#lines + 1] = "Name:        " .. module
2007ed84fa1SKyle Evans		if info.name then
2017ed84fa1SKyle Evans			lines[#lines + 1] = "Path:        " .. info.name
2027ed84fa1SKyle Evans		end
2037ed84fa1SKyle Evans
2047ed84fa1SKyle Evans		if info.type then
2057ed84fa1SKyle Evans			lines[#lines + 1] = "Type:        " .. info.type
2067ed84fa1SKyle Evans		end
2077ed84fa1SKyle Evans
2087ed84fa1SKyle Evans		if info.flags then
2097ed84fa1SKyle Evans			lines[#lines + 1] = "Flags:       " .. info.flags
2107ed84fa1SKyle Evans		end
2117ed84fa1SKyle Evans
2127ed84fa1SKyle Evans		if info.before then
2137ed84fa1SKyle Evans			lines[#lines + 1] = "Before load: " .. info.before
2147ed84fa1SKyle Evans		end
2157ed84fa1SKyle Evans
2167ed84fa1SKyle Evans		if info.after then
2177ed84fa1SKyle Evans			lines[#lines + 1] = "After load:  " .. info.after
2187ed84fa1SKyle Evans		end
2197ed84fa1SKyle Evans
2207ed84fa1SKyle Evans		if info.error then
2217ed84fa1SKyle Evans			lines[#lines + 1] = "Error:       " .. info.error
2227ed84fa1SKyle Evans		end
2237ed84fa1SKyle Evans
2247ed84fa1SKyle Evans		local status
2257ed84fa1SKyle Evans		if blacklist[module] and not info.force then
2267ed84fa1SKyle Evans			status = "Blacklisted"
2277ed84fa1SKyle Evans		elseif info.load == "YES" then
2287ed84fa1SKyle Evans			status = "Load"
2297ed84fa1SKyle Evans		else
2307ed84fa1SKyle Evans			status = "Don't load"
2317ed84fa1SKyle Evans		end
2327ed84fa1SKyle Evans
2337ed84fa1SKyle Evans		lines[#lines + 1] = "Status:      " .. status
2347ed84fa1SKyle Evans	end
2357ed84fa1SKyle Evans
2367ed84fa1SKyle Evans	pager.open()
23729842cb3SKyle Evans	for _, v in ipairs(lines) do
2387ed84fa1SKyle Evans		pager.output(v .. "\n")
2397ed84fa1SKyle Evans	end
2407ed84fa1SKyle Evans	pager.close()
2417ed84fa1SKyle Evansend
2427ed84fa1SKyle Evans
243*25b4b24eSWarner Loshcli["disable-device"] = function(...)
244*25b4b24eSWarner Losh	local _, argv = cli.arguments(...)
245*25b4b24eSWarner Losh	local d, u
246*25b4b24eSWarner Losh
247*25b4b24eSWarner Losh	if #argv == 0 then
248*25b4b24eSWarner Losh		print("usage error: disable-device device")
249*25b4b24eSWarner Losh		return
250*25b4b24eSWarner Losh	end
251*25b4b24eSWarner Losh
252*25b4b24eSWarner Losh	d, u = string.match(argv[1], "(%w*%a)(%d+)")
253*25b4b24eSWarner Losh	if d ~= nil then
254*25b4b24eSWarner Losh		loader.setenv("hint." .. d .. "." .. u .. ".disabled", "1")
255*25b4b24eSWarner Losh	end
256*25b4b24eSWarner Loshend
257*25b4b24eSWarner Losh
2582e4dad82SKyle Evans-- Used for splitting cli varargs into cmd_name and the rest of argv
259eca5ca66SKyle Evansfunction cli.arguments(...)
260eca5ca66SKyle Evans	local argv = {...}
261e2df27e3SKyle Evans	local cmd_name
262eca5ca66SKyle Evans	cmd_name, argv = core.popFrontTable(argv)
263eca5ca66SKyle Evans	return cmd_name, argv
264eca5ca66SKyle Evansend
265eca5ca66SKyle Evans
266e37f4622SKyle Evansreturn cli
267