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 42ba25195eSWarner Losh /* 43ba25195eSWarner Losh * Interactive mode 44ba25195eSWarner Losh */ 45ba25195eSWarner Losh void 466bc86037SWarner Losh interact(void) 47ba25195eSWarner Losh { 48ba25195eSWarner Losh static char input[256]; /* big enough? */ 49*2583c337SKyle Evans const char * volatile interp_identifier; 50ba25195eSWarner Losh 51*2583c337SKyle Evans /* 52*2583c337SKyle Evans * Because interp_identifier is volatile, it cannot be optimized out by 53*2583c337SKyle Evans * the compiler as it's considered an externally observable event. This 54*2583c337SKyle Evans * prevents the compiler from optimizing out our carefully placed 55*2583c337SKyle Evans * $Interpreter:4th string that userboot may use to determine that 56*2583c337SKyle Evans * we need to switch interpreters. 57*2583c337SKyle Evans */ 58*2583c337SKyle Evans interp_identifier = bootprog_interp; 5979a6a17aSWarner Losh interp_init(); 60ba25195eSWarner Losh 61ba25195eSWarner Losh printf("\n"); 62ba25195eSWarner Losh 63ba25195eSWarner Losh /* 64ba25195eSWarner Losh * Before interacting, we might want to autoboot. 65ba25195eSWarner Losh */ 66ba25195eSWarner Losh autoboot_maybe(); 67ba25195eSWarner Losh 68ba25195eSWarner Losh /* 69ba25195eSWarner Losh * Not autobooting, go manual 70ba25195eSWarner Losh */ 71ba25195eSWarner Losh printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 72ba25195eSWarner Losh if (getenv("prompt") == NULL) 73ba25195eSWarner Losh setenv("prompt", "${interpret}", 1); 74ba25195eSWarner Losh if (getenv("interpret") == NULL) 75ba25195eSWarner Losh setenv("interpret", "OK", 1); 76ba25195eSWarner Losh 77ba25195eSWarner Losh for (;;) { 78ba25195eSWarner Losh input[0] = '\0'; 7979a6a17aSWarner Losh interp_emit_prompt(); 80ba25195eSWarner Losh ngets(input, sizeof(input)); 8179a6a17aSWarner Losh interp_run(input); 82ba25195eSWarner Losh } 83ba25195eSWarner Losh } 84ba25195eSWarner Losh 85ba25195eSWarner Losh /* 86ba25195eSWarner Losh * Read commands from a file, then execute them. 87ba25195eSWarner Losh * 88ba25195eSWarner Losh * We store the commands in memory and close the source file so that the media 89ba25195eSWarner Losh * holding it can safely go away while we are executing. 90ba25195eSWarner Losh * 91ba25195eSWarner Losh * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so 92ba25195eSWarner Losh * that the script won't stop if they fail). 93ba25195eSWarner Losh */ 94ba25195eSWarner Losh COMMAND_SET(include, "include", "read commands from a file", command_include); 95ba25195eSWarner Losh 96ba25195eSWarner Losh static int 97ba25195eSWarner Losh command_include(int argc, char *argv[]) 98ba25195eSWarner Losh { 99ba25195eSWarner Losh int i; 100ba25195eSWarner Losh int res; 101ba25195eSWarner Losh char **argvbuf; 102ba25195eSWarner Losh 103ba25195eSWarner Losh /* 104ba25195eSWarner Losh * Since argv is static, we need to save it here. 105ba25195eSWarner Losh */ 106ba25195eSWarner Losh argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); 107ba25195eSWarner Losh for (i = 0; i < argc; i++) 108ba25195eSWarner Losh argvbuf[i] = strdup(argv[i]); 109ba25195eSWarner Losh 110ba25195eSWarner Losh res=CMD_OK; 111ba25195eSWarner Losh for (i = 1; (i < argc) && (res == CMD_OK); i++) 11279a6a17aSWarner Losh res = interp_include(argvbuf[i]); 113ba25195eSWarner Losh 114ba25195eSWarner Losh for (i = 0; i < argc; i++) 115ba25195eSWarner Losh free(argvbuf[i]); 116ba25195eSWarner Losh free(argvbuf); 117ba25195eSWarner Losh 118ba25195eSWarner Losh return(res); 119ba25195eSWarner Losh } 120ba25195eSWarner Losh 121ba25195eSWarner Losh /* 122ca987d46SWarner Losh * Emit the current prompt; use the same syntax as the parser 12379a6a17aSWarner Losh * for embedding environment variables. Does not accept input. 124ca987d46SWarner Losh */ 12579a6a17aSWarner Losh void 12679a6a17aSWarner Losh interp_emit_prompt(void) 127ca987d46SWarner Losh { 128ca987d46SWarner Losh char *pr, *p, *cp, *ev; 129ca987d46SWarner Losh 130ca987d46SWarner Losh if ((cp = getenv("prompt")) == NULL) 131ca987d46SWarner Losh cp = ">"; 132ca987d46SWarner Losh pr = p = strdup(cp); 133ca987d46SWarner Losh 134ca987d46SWarner Losh while (*p != 0) { 135ca987d46SWarner Losh if ((*p == '$') && (*(p+1) == '{')) { 136ca987d46SWarner Losh for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 137ca987d46SWarner Losh ; 138ca987d46SWarner Losh *cp = 0; 139ca987d46SWarner Losh ev = getenv(p + 2); 140ca987d46SWarner Losh 141ca987d46SWarner Losh if (ev != NULL) 142ca987d46SWarner Losh printf("%s", ev); 143ca987d46SWarner Losh p = cp + 1; 144ca987d46SWarner Losh continue; 145ca987d46SWarner Losh } 146ca987d46SWarner Losh putchar(*p++); 147ca987d46SWarner Losh } 148ca987d46SWarner Losh putchar(' '); 149ca987d46SWarner Losh free(pr); 150ca987d46SWarner Losh } 1513a4a3639SWarner Losh 1523a4a3639SWarner Losh /* 1533a4a3639SWarner Losh * Perform a builtin command 1543a4a3639SWarner Losh */ 1553a4a3639SWarner Losh int 1563a4a3639SWarner Losh interp_builtin_cmd(int argc, char *argv[]) 1573a4a3639SWarner Losh { 1583a4a3639SWarner Losh int result; 1593a4a3639SWarner Losh struct bootblk_command **cmdp; 1603a4a3639SWarner Losh bootblk_cmd_t *cmd; 1613a4a3639SWarner Losh 1623a4a3639SWarner Losh if (argc < 1) 1633a4a3639SWarner Losh return(CMD_OK); 1643a4a3639SWarner Losh 1653a4a3639SWarner Losh /* set return defaults; a successful command will override these */ 1663a4a3639SWarner Losh command_errmsg = command_errbuf; 1673a4a3639SWarner Losh strcpy(command_errbuf, "no error message"); 1683a4a3639SWarner Losh cmd = NULL; 1693a4a3639SWarner Losh result = CMD_ERROR; 1703a4a3639SWarner Losh 1713a4a3639SWarner Losh /* search the command set for the command */ 1723a4a3639SWarner Losh SET_FOREACH(cmdp, Xcommand_set) { 1733a4a3639SWarner Losh if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name)) 1743a4a3639SWarner Losh cmd = (*cmdp)->c_fn; 1753a4a3639SWarner Losh } 1763a4a3639SWarner Losh if (cmd != NULL) { 1773a4a3639SWarner Losh result = (cmd)(argc, argv); 1783a4a3639SWarner Losh } else { 1793a4a3639SWarner Losh command_errmsg = "unknown command"; 1803a4a3639SWarner Losh } 1813a4a3639SWarner Losh return(result); 1823a4a3639SWarner Losh } 183