1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7ca987d46SWarner Losh * are met: 8ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13ca987d46SWarner Losh * 14ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca987d46SWarner Losh * SUCH DAMAGE. 25ca987d46SWarner Losh */ 26ba25195eSWarner Losh 27ca987d46SWarner Losh #include <sys/cdefs.h> 28ca987d46SWarner Losh /* 29ca987d46SWarner Losh * Simple commandline interpreter, toplevel and misc. 30ca987d46SWarner Losh * 31ca987d46SWarner Losh * XXX may be obsoleted by BootFORTH or some other, better, interpreter. 32ca987d46SWarner Losh */ 33ca987d46SWarner Losh 34ca987d46SWarner Losh #include <stand.h> 35ca987d46SWarner Losh #include <string.h> 36ca987d46SWarner Losh #include "bootstrap.h" 37ca987d46SWarner Losh 38*f616d61aSSimon J. Gerraty #ifdef LOADER_VERIEXEC 39*f616d61aSSimon J. Gerraty #include <verify_file.h> 40*f616d61aSSimon J. Gerraty #endif 41*f616d61aSSimon J. Gerraty 42ca987d46SWarner Losh #define MAXARGS 20 /* maximum number of arguments allowed */ 43ca987d46SWarner Losh 44f4d71d0cSWarner Losh const char * volatile interp_identifier; 45f4d71d0cSWarner Losh 46ba25195eSWarner Losh /* 47ba25195eSWarner Losh * Interactive mode 48ba25195eSWarner Losh */ 49ba25195eSWarner Losh void 506bc86037SWarner Losh interact(void) 51ba25195eSWarner Losh { 52ba25195eSWarner Losh static char input[256]; /* big enough? */ 53ba25195eSWarner Losh 54313724baSColin Percival TSENTER(); 55313724baSColin Percival 562583c337SKyle Evans /* 572583c337SKyle Evans * Because interp_identifier is volatile, it cannot be optimized out by 582583c337SKyle Evans * the compiler as it's considered an externally observable event. This 592583c337SKyle Evans * prevents the compiler from optimizing out our carefully placed 602583c337SKyle Evans * $Interpreter:4th string that userboot may use to determine that 612583c337SKyle Evans * we need to switch interpreters. 622583c337SKyle Evans */ 632583c337SKyle Evans interp_identifier = bootprog_interp; 6479a6a17aSWarner Losh interp_init(); 65ba25195eSWarner Losh 66ba25195eSWarner Losh printf("\n"); 67ba25195eSWarner Losh 68ba25195eSWarner Losh /* 69ba25195eSWarner Losh * Before interacting, we might want to autoboot. 70ba25195eSWarner Losh */ 71ba25195eSWarner Losh autoboot_maybe(); 72ba25195eSWarner Losh 73ba25195eSWarner Losh /* 74ba25195eSWarner Losh * Not autobooting, go manual 75ba25195eSWarner Losh */ 76ba25195eSWarner Losh printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 77ba25195eSWarner Losh if (getenv("prompt") == NULL) 78ba25195eSWarner Losh setenv("prompt", "${interpret}", 1); 79ba25195eSWarner Losh if (getenv("interpret") == NULL) 80ba25195eSWarner Losh setenv("interpret", "OK", 1); 81ba25195eSWarner Losh 82ba25195eSWarner Losh for (;;) { 83ba25195eSWarner Losh input[0] = '\0'; 8479a6a17aSWarner Losh interp_emit_prompt(); 85ba25195eSWarner Losh ngets(input, sizeof(input)); 86*f616d61aSSimon J. Gerraty #ifdef LOADER_VERIEXEC 87*f616d61aSSimon J. Gerraty /* some settings should be restritcted */ 88*f616d61aSSimon J. Gerraty ve_status_set(-1, VE_UNVERIFIED_OK); 89*f616d61aSSimon J. Gerraty #endif 9079a6a17aSWarner Losh interp_run(input); 91ba25195eSWarner Losh } 92ba25195eSWarner Losh } 93ba25195eSWarner Losh 94ba25195eSWarner Losh /* 95ba25195eSWarner Losh * Read commands from a file, then execute them. 96ba25195eSWarner Losh * 97ba25195eSWarner Losh * We store the commands in memory and close the source file so that the media 98ba25195eSWarner Losh * holding it can safely go away while we are executing. 99ba25195eSWarner Losh * 100ba25195eSWarner Losh * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so 101ba25195eSWarner Losh * that the script won't stop if they fail). 102ba25195eSWarner Losh */ 103ba25195eSWarner Losh COMMAND_SET(include, "include", "read commands from a file", command_include); 104ba25195eSWarner Losh 105ba25195eSWarner Losh static int 106ba25195eSWarner Losh command_include(int argc, char *argv[]) 107ba25195eSWarner Losh { 108ba25195eSWarner Losh int i; 109ba25195eSWarner Losh int res; 110ba25195eSWarner Losh char **argvbuf; 111ba25195eSWarner Losh 112ba25195eSWarner Losh /* 113ba25195eSWarner Losh * Since argv is static, we need to save it here. 114ba25195eSWarner Losh */ 115ba25195eSWarner Losh argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); 116ba25195eSWarner Losh for (i = 0; i < argc; i++) 117ba25195eSWarner Losh argvbuf[i] = strdup(argv[i]); 118ba25195eSWarner Losh 119ba25195eSWarner Losh res=CMD_OK; 120ba25195eSWarner Losh for (i = 1; (i < argc) && (res == CMD_OK); i++) 12179a6a17aSWarner Losh res = interp_include(argvbuf[i]); 122ba25195eSWarner Losh 123ba25195eSWarner Losh for (i = 0; i < argc; i++) 124ba25195eSWarner Losh free(argvbuf[i]); 125ba25195eSWarner Losh free(argvbuf); 126ba25195eSWarner Losh 127ba25195eSWarner Losh return(res); 128ba25195eSWarner Losh } 129ba25195eSWarner Losh 130ba25195eSWarner Losh /* 131ca987d46SWarner Losh * Emit the current prompt; use the same syntax as the parser 13279a6a17aSWarner Losh * for embedding environment variables. Does not accept input. 133ca987d46SWarner Losh */ 13479a6a17aSWarner Losh void 13579a6a17aSWarner Losh interp_emit_prompt(void) 136ca987d46SWarner Losh { 137ca987d46SWarner Losh char *pr, *p, *cp, *ev; 138ca987d46SWarner Losh 139ca987d46SWarner Losh if ((cp = getenv("prompt")) == NULL) 140ca987d46SWarner Losh cp = ">"; 141ca987d46SWarner Losh pr = p = strdup(cp); 142ca987d46SWarner Losh 143ca987d46SWarner Losh while (*p != 0) { 144ca987d46SWarner Losh if ((*p == '$') && (*(p+1) == '{')) { 145ca987d46SWarner Losh for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 146ca987d46SWarner Losh ; 147ca987d46SWarner Losh *cp = 0; 148ca987d46SWarner Losh ev = getenv(p + 2); 149ca987d46SWarner Losh 150ca987d46SWarner Losh if (ev != NULL) 151ca987d46SWarner Losh printf("%s", ev); 152ca987d46SWarner Losh p = cp + 1; 153ca987d46SWarner Losh continue; 154ca987d46SWarner Losh } 155ca987d46SWarner Losh putchar(*p++); 156ca987d46SWarner Losh } 157ca987d46SWarner Losh putchar(' '); 158ca987d46SWarner Losh free(pr); 159ca987d46SWarner Losh } 1603a4a3639SWarner Losh 161113dfaddSWarner Losh static struct bootblk_command * 162113dfaddSWarner Losh interp_lookup_cmd(const char *cmd) 163113dfaddSWarner Losh { 164113dfaddSWarner Losh struct bootblk_command **cmdp; 165113dfaddSWarner Losh 166113dfaddSWarner Losh /* search the command set for the command */ 167113dfaddSWarner Losh SET_FOREACH(cmdp, Xcommand_set) { 168113dfaddSWarner Losh if (((*cmdp)->c_name != NULL) && !strcmp(cmd, (*cmdp)->c_name)) 169113dfaddSWarner Losh return (*cmdp); 170113dfaddSWarner Losh } 171113dfaddSWarner Losh return (NULL); 172113dfaddSWarner Losh } 173113dfaddSWarner Losh 1743a4a3639SWarner Losh /* 1753a4a3639SWarner Losh * Perform a builtin command 1763a4a3639SWarner Losh */ 1773a4a3639SWarner Losh int 1783a4a3639SWarner Losh interp_builtin_cmd(int argc, char *argv[]) 1793a4a3639SWarner Losh { 1803a4a3639SWarner Losh int result; 181113dfaddSWarner Losh struct bootblk_command *cmd; 1823a4a3639SWarner Losh 1833a4a3639SWarner Losh if (argc < 1) 1843a4a3639SWarner Losh return (CMD_OK); 1853a4a3639SWarner Losh 1863a4a3639SWarner Losh /* set return defaults; a successful command will override these */ 1873a4a3639SWarner Losh command_errmsg = command_errbuf; 1883a4a3639SWarner Losh strcpy(command_errbuf, "no error message"); 1893a4a3639SWarner Losh result = CMD_ERROR; 1903a4a3639SWarner Losh 191113dfaddSWarner Losh cmd = interp_lookup_cmd(argv[0]); 192113dfaddSWarner Losh if (cmd != NULL && cmd->c_fn) { 193113dfaddSWarner Losh result = cmd->c_fn(argc, argv); 1943a4a3639SWarner Losh } else { 1953a4a3639SWarner Losh command_errmsg = "unknown command"; 1963a4a3639SWarner Losh } 1973a4a3639SWarner Losh return (result); 1983a4a3639SWarner Losh } 199a5948d40SWarner Losh 200a5948d40SWarner Losh /* 201a5948d40SWarner Losh * Return true if the builtin command exists 202a5948d40SWarner Losh */ 203a5948d40SWarner Losh bool 204a5948d40SWarner Losh interp_has_builtin_cmd(const char *cmd) 205a5948d40SWarner Losh { 206a5948d40SWarner Losh return (interp_lookup_cmd(cmd) != NULL); 207a5948d40SWarner Losh } 208