1-- 2-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3-- 4-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 5-- 6-- Redistribution and use in source and binary forms, with or without 7-- modification, are permitted provided that the following conditions 8-- are met: 9-- 1. Redistributions of source code must retain the above copyright 10-- notice, this list of conditions and the following disclaimer. 11-- 2. Redistributions in binary form must reproduce the above copyright 12-- notice, this list of conditions and the following disclaimer in the 13-- documentation and/or other materials provided with the distribution. 14-- 15-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25-- SUCH DAMAGE. 26-- 27-- $FreeBSD$ 28-- 29 30local config = require("config") 31local core = require("core") 32 33local cli = {} 34 35-- Internal function 36-- Parses arguments to boot and returns two values: kernel_name, argstr 37-- Defaults to nil and "" respectively. 38-- This will also parse arguments to autoboot, but the with_kernel argument 39-- will need to be explicitly overwritten to false 40local function parseBootArgs(argv, with_kernel) 41 if with_kernel == nil then 42 with_kernel = true 43 end 44 if #argv == 0 then 45 if with_kernel then 46 return nil, "" 47 else 48 return "" 49 end 50 end 51 local kernel_name 52 local argstr = "" 53 54 for _, v in ipairs(argv) do 55 if with_kernel and v:sub(1,1) ~= "-" then 56 kernel_name = v 57 else 58 argstr = argstr .. " " .. v 59 end 60 end 61 if with_kernel then 62 return kernel_name, argstr 63 else 64 return argstr 65 end 66end 67 68local function setModule(module, loading) 69 if loading and config.enableModule(module) then 70 print(module .. " will be loaded") 71 elseif not loading and config.disableModule(module) then 72 print(module .. " will not be loaded") 73 end 74end 75 76-- Declares a global function cli_execute that attempts to dispatch the 77-- arguments passed as a lua function. This gives lua a chance to intercept 78-- builtin CLI commands like "boot" 79-- This function intentionally does not follow our general naming guideline for 80-- functions. This is global pollution, but the clearly separated 'cli' looks 81-- more like a module indicator to serve as a hint of where to look for the 82-- corresponding definition. 83function cli_execute(...) 84 local argv = {...} 85 -- Just in case... 86 if #argv == 0 then 87 return loader.command(...) 88 end 89 90 local cmd_name = argv[1] 91 local cmd = cli[cmd_name] 92 if cmd ~= nil and type(cmd) == "function" then 93 -- Pass argv wholesale into cmd. We could omit argv[0] since the 94 -- traditional reasons for including it don't necessarily apply, 95 -- it may not be totally redundant if we want to have one global 96 -- handling multiple commands 97 return cmd(...) 98 else 99 return loader.command(...) 100 end 101 102end 103 104function cli_execute_unparsed(str) 105 return cli_execute(loader.parse(str)) 106end 107 108-- Module exports 109 110function cli.boot(...) 111 local _, argv = cli.arguments(...) 112 local kernel, argstr = parseBootArgs(argv) 113 if kernel ~= nil then 114 loader.perform("unload") 115 config.selectKernel(kernel) 116 end 117 core.boot(argstr) 118end 119 120function cli.autoboot(...) 121 local _, argv = cli.arguments(...) 122 local argstr = parseBootArgs(argv, false) 123 core.autoboot(argstr) 124end 125 126cli['boot-conf'] = function(...) 127 local _, argv = cli.arguments(...) 128 local kernel, argstr = parseBootArgs(argv) 129 if kernel ~= nil then 130 loader.perform("unload") 131 config.selectKernel(kernel) 132 end 133 core.autoboot(argstr) 134end 135 136cli['read-conf'] = function(...) 137 local _, argv = cli.arguments(...) 138 config.readConf(assert(core.popFrontTable(argv))) 139end 140 141cli['reload-conf'] = function() 142 config.reload() 143end 144 145cli["enable-module"] = function(...) 146 local _, argv = cli.arguments(...) 147 if #argv == 0 then 148 print("usage error: enable-module module") 149 return 150 end 151 152 setModule(argv[1], true) 153end 154 155cli["disable-module"] = function(...) 156 local _, argv = cli.arguments(...) 157 if #argv == 0 then 158 print("usage error: disable-module module") 159 return 160 end 161 162 setModule(argv[1], false) 163end 164 165cli["toggle-module"] = function(...) 166 local _, argv = cli.arguments(...) 167 if #argv == 0 then 168 print("usage error: toggle-module module") 169 return 170 end 171 172 local module = argv[1] 173 setModule(module, not config.isModuleEnabled(module)) 174end 175 176-- Used for splitting cli varargs into cmd_name and the rest of argv 177function cli.arguments(...) 178 local argv = {...} 179 local cmd_name 180 cmd_name, argv = core.popFrontTable(argv) 181 return cmd_name, argv 182end 183 184return cli 185