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 __FBSDID("$FreeBSD$"); 29ca987d46SWarner Losh 30ca987d46SWarner Losh /* 31ca987d46SWarner Losh * Simple commandline interpreter, toplevel and misc. 32ca987d46SWarner Losh * 33ca987d46SWarner Losh * XXX may be obsoleted by BootFORTH or some other, better, interpreter. 34ca987d46SWarner Losh */ 35ca987d46SWarner Losh 36ca987d46SWarner Losh #include <stand.h> 37ca987d46SWarner Losh #include <string.h> 38ca987d46SWarner Losh #include "bootstrap.h" 39ca987d46SWarner Losh 40ca987d46SWarner Losh #define MAXARGS 20 /* maximum number of arguments allowed */ 41ca987d46SWarner Losh 42f4d71d0cSWarner Losh const char * volatile interp_identifier; 43f4d71d0cSWarner Losh 44ba25195eSWarner Losh /* 45ba25195eSWarner Losh * Interactive mode 46ba25195eSWarner Losh */ 47ba25195eSWarner Losh void 486bc86037SWarner Losh interact(void) 49ba25195eSWarner Losh { 50ba25195eSWarner Losh static char input[256]; /* big enough? */ 51ba25195eSWarner Losh 52313724baSColin Percival TSENTER(); 53313724baSColin Percival 542583c337SKyle Evans /* 552583c337SKyle Evans * Because interp_identifier is volatile, it cannot be optimized out by 562583c337SKyle Evans * the compiler as it's considered an externally observable event. This 572583c337SKyle Evans * prevents the compiler from optimizing out our carefully placed 582583c337SKyle Evans * $Interpreter:4th string that userboot may use to determine that 592583c337SKyle Evans * we need to switch interpreters. 602583c337SKyle Evans */ 612583c337SKyle Evans interp_identifier = bootprog_interp; 6279a6a17aSWarner Losh interp_init(); 63ba25195eSWarner Losh 64ba25195eSWarner Losh printf("\n"); 65ba25195eSWarner Losh 66ba25195eSWarner Losh /* 67ba25195eSWarner Losh * Before interacting, we might want to autoboot. 68ba25195eSWarner Losh */ 69ba25195eSWarner Losh autoboot_maybe(); 70ba25195eSWarner Losh 71ba25195eSWarner Losh /* 72ba25195eSWarner Losh * Not autobooting, go manual 73ba25195eSWarner Losh */ 74ba25195eSWarner Losh printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 75ba25195eSWarner Losh if (getenv("prompt") == NULL) 76ba25195eSWarner Losh setenv("prompt", "${interpret}", 1); 77ba25195eSWarner Losh if (getenv("interpret") == NULL) 78ba25195eSWarner Losh setenv("interpret", "OK", 1); 79ba25195eSWarner Losh 80ba25195eSWarner Losh for (;;) { 81ba25195eSWarner Losh input[0] = '\0'; 8279a6a17aSWarner Losh interp_emit_prompt(); 83ba25195eSWarner Losh ngets(input, sizeof(input)); 8479a6a17aSWarner Losh interp_run(input); 85ba25195eSWarner Losh } 86ba25195eSWarner Losh } 87ba25195eSWarner Losh 88ba25195eSWarner Losh /* 89ba25195eSWarner Losh * Read commands from a file, then execute them. 90ba25195eSWarner Losh * 91ba25195eSWarner Losh * We store the commands in memory and close the source file so that the media 92ba25195eSWarner Losh * holding it can safely go away while we are executing. 93ba25195eSWarner Losh * 94ba25195eSWarner Losh * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so 95ba25195eSWarner Losh * that the script won't stop if they fail). 96ba25195eSWarner Losh */ 97ba25195eSWarner Losh COMMAND_SET(include, "include", "read commands from a file", command_include); 98ba25195eSWarner Losh 99ba25195eSWarner Losh static int 100ba25195eSWarner Losh command_include(int argc, char *argv[]) 101ba25195eSWarner Losh { 102ba25195eSWarner Losh int i; 103ba25195eSWarner Losh int res; 104ba25195eSWarner Losh char **argvbuf; 105ba25195eSWarner Losh 106ba25195eSWarner Losh /* 107ba25195eSWarner Losh * Since argv is static, we need to save it here. 108ba25195eSWarner Losh */ 109ba25195eSWarner Losh argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); 110ba25195eSWarner Losh for (i = 0; i < argc; i++) 111ba25195eSWarner Losh argvbuf[i] = strdup(argv[i]); 112ba25195eSWarner Losh 113ba25195eSWarner Losh res=CMD_OK; 114ba25195eSWarner Losh for (i = 1; (i < argc) && (res == CMD_OK); i++) 11579a6a17aSWarner Losh res = interp_include(argvbuf[i]); 116ba25195eSWarner Losh 117ba25195eSWarner Losh for (i = 0; i < argc; i++) 118ba25195eSWarner Losh free(argvbuf[i]); 119ba25195eSWarner Losh free(argvbuf); 120ba25195eSWarner Losh 121ba25195eSWarner Losh return(res); 122ba25195eSWarner Losh } 123ba25195eSWarner Losh 124ba25195eSWarner Losh /* 125ca987d46SWarner Losh * Emit the current prompt; use the same syntax as the parser 12679a6a17aSWarner Losh * for embedding environment variables. Does not accept input. 127ca987d46SWarner Losh */ 12879a6a17aSWarner Losh void 12979a6a17aSWarner Losh interp_emit_prompt(void) 130ca987d46SWarner Losh { 131ca987d46SWarner Losh char *pr, *p, *cp, *ev; 132ca987d46SWarner Losh 133ca987d46SWarner Losh if ((cp = getenv("prompt")) == NULL) 134ca987d46SWarner Losh cp = ">"; 135ca987d46SWarner Losh pr = p = strdup(cp); 136ca987d46SWarner Losh 137ca987d46SWarner Losh while (*p != 0) { 138ca987d46SWarner Losh if ((*p == '$') && (*(p+1) == '{')) { 139ca987d46SWarner Losh for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 140ca987d46SWarner Losh ; 141ca987d46SWarner Losh *cp = 0; 142ca987d46SWarner Losh ev = getenv(p + 2); 143ca987d46SWarner Losh 144ca987d46SWarner Losh if (ev != NULL) 145ca987d46SWarner Losh printf("%s", ev); 146ca987d46SWarner Losh p = cp + 1; 147ca987d46SWarner Losh continue; 148ca987d46SWarner Losh } 149ca987d46SWarner Losh putchar(*p++); 150ca987d46SWarner Losh } 151ca987d46SWarner Losh putchar(' '); 152ca987d46SWarner Losh free(pr); 153ca987d46SWarner Losh } 1543a4a3639SWarner Losh 155113dfaddSWarner Losh static struct bootblk_command * 156113dfaddSWarner Losh interp_lookup_cmd(const char *cmd) 157113dfaddSWarner Losh { 158113dfaddSWarner Losh struct bootblk_command **cmdp; 159113dfaddSWarner Losh 160113dfaddSWarner Losh /* search the command set for the command */ 161113dfaddSWarner Losh SET_FOREACH(cmdp, Xcommand_set) { 162113dfaddSWarner Losh if (((*cmdp)->c_name != NULL) && !strcmp(cmd, (*cmdp)->c_name)) 163113dfaddSWarner Losh return (*cmdp); 164113dfaddSWarner Losh } 165113dfaddSWarner Losh return (NULL); 166113dfaddSWarner Losh } 167113dfaddSWarner Losh 1683a4a3639SWarner Losh /* 1693a4a3639SWarner Losh * Perform a builtin command 1703a4a3639SWarner Losh */ 1713a4a3639SWarner Losh int 1723a4a3639SWarner Losh interp_builtin_cmd(int argc, char *argv[]) 1733a4a3639SWarner Losh { 1743a4a3639SWarner Losh int result; 175113dfaddSWarner Losh struct bootblk_command *cmd; 1763a4a3639SWarner Losh 1773a4a3639SWarner Losh if (argc < 1) 1783a4a3639SWarner Losh return (CMD_OK); 1793a4a3639SWarner Losh 1803a4a3639SWarner Losh /* set return defaults; a successful command will override these */ 1813a4a3639SWarner Losh command_errmsg = command_errbuf; 1823a4a3639SWarner Losh strcpy(command_errbuf, "no error message"); 1833a4a3639SWarner Losh result = CMD_ERROR; 1843a4a3639SWarner Losh 185113dfaddSWarner Losh cmd = interp_lookup_cmd(argv[0]); 186113dfaddSWarner Losh if (cmd != NULL && cmd->c_fn) { 187113dfaddSWarner Losh result = cmd->c_fn(argc, argv); 1883a4a3639SWarner Losh } else { 1893a4a3639SWarner Losh command_errmsg = "unknown command"; 1903a4a3639SWarner Losh } 1913a4a3639SWarner Losh return (result); 1923a4a3639SWarner Losh } 193*a5948d40SWarner Losh 194*a5948d40SWarner Losh /* 195*a5948d40SWarner Losh * Return true if the builtin command exists 196*a5948d40SWarner Losh */ 197*a5948d40SWarner Losh bool 198*a5948d40SWarner Losh interp_has_builtin_cmd(const char *cmd) 199*a5948d40SWarner Losh { 200*a5948d40SWarner Losh return (interp_lookup_cmd(cmd) != NULL); 201*a5948d40SWarner Losh } 202