/*-1* Copyright (c) 1998 Michael Smith <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526/*27* Simple commandline interpreter, toplevel and misc.28*29* XXX may be obsoleted by BootFORTH or some other, better, interpreter.30*/3132#include <stand.h>33#include <string.h>34#include "bootstrap.h"3536#ifdef LOADER_VERIEXEC37#include <verify_file.h>38#endif3940#define MAXARGS 20 /* maximum number of arguments allowed */4142const char * volatile interp_identifier;4344/*45* Interactive mode46*/47void48interact(void)49{50static char input[256]; /* big enough? */5152TSENTER();5354/*55* Because interp_identifier is volatile, it cannot be optimized out by56* the compiler as it's considered an externally observable event. This57* prevents the compiler from optimizing out our carefully placed58* $Interpreter:4th string that userboot may use to determine that59* we need to switch interpreters.60*/61interp_identifier = bootprog_interp;62interp_preinit();63interp_init();6465printf("\n");6667/*68* Before interacting, we might want to autoboot.69*/70autoboot_maybe();7172/*73* Not autobooting, go manual74*/75printf("\nType '?' for a list of commands, 'help' for more detailed help.\n");76if (getenv("prompt") == NULL)77setenv("prompt", "${interpret}", 1);78if (getenv("interpret") == NULL)79setenv("interpret", "OK", 1);8081for (;;) {82input[0] = '\0';83interp_emit_prompt();84ngets(input, sizeof(input));85#ifdef LOADER_VERIEXEC86/* some settings should be restritcted */87ve_status_set(-1, VE_UNVERIFIED_OK);88#endif89interp_run(input);90}91}9293/*94* Read commands from a file, then execute them.95*96* We store the commands in memory and close the source file so that the media97* holding it can safely go away while we are executing.98*99* Commands may be prefixed with '@' (so they aren't displayed) or '-' (so100* that the script won't stop if they fail).101*/102COMMAND_SET(include, "include", "read commands from a file", command_include);103104static int105command_include(int argc, char *argv[])106{107int i;108int res;109char **argvbuf;110111/*112* Since argv is static, we need to save it here.113*/114argvbuf = (char**) calloc((u_int)argc, sizeof(char*));115for (i = 0; i < argc; i++)116argvbuf[i] = strdup(argv[i]);117118res=CMD_OK;119for (i = 1; (i < argc) && (res == CMD_OK); i++)120res = interp_include(argvbuf[i]);121122for (i = 0; i < argc; i++)123free(argvbuf[i]);124free(argvbuf);125126return(res);127}128129/*130* Emit the current prompt; use the same syntax as the parser131* for embedding environment variables. Does not accept input.132*/133void134interp_emit_prompt(void)135{136char *pr, *p, *cp, *ev;137138if ((cp = getenv("prompt")) == NULL)139cp = ">";140pr = p = strdup(cp);141142while (*p != 0) {143if ((*p == '$') && (*(p+1) == '{')) {144for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++)145;146*cp = 0;147ev = getenv(p + 2);148149if (ev != NULL)150printf("%s", ev);151p = cp + 1;152continue;153}154putchar(*p++);155}156putchar(' ');157free(pr);158}159160static struct bootblk_command *161interp_lookup_cmd(const char *cmd)162{163struct bootblk_command **cmdp;164165/* search the command set for the command */166SET_FOREACH(cmdp, Xcommand_set) {167if (((*cmdp)->c_name != NULL) && !strcmp(cmd, (*cmdp)->c_name))168return (*cmdp);169}170return (NULL);171}172173/*174* Perform a builtin command175*/176int177interp_builtin_cmd(int argc, char *argv[])178{179int result;180struct bootblk_command *cmd;181182if (argc < 1)183return (CMD_OK);184185/* set return defaults; a successful command will override these */186command_errmsg = command_errbuf;187strcpy(command_errbuf, "no error message");188result = CMD_ERROR;189190cmd = interp_lookup_cmd(argv[0]);191if (cmd != NULL && cmd->c_fn) {192TSENTER2(argv[0]);193result = cmd->c_fn(argc, argv);194TSEXIT();195} else {196command_errmsg = "unknown command";197}198return (result);199}200201/*202* Return true if the builtin command exists203*/204bool205interp_has_builtin_cmd(const char *cmd)206{207return (interp_lookup_cmd(cmd) != NULL);208}209210211