interp.c revision 40106
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: interp.c,v 1.5 1998/10/07 02:38:26 msmith Exp $ 27 */ 28/* 29 * Simple commandline interpreter, toplevel and misc. 30 * 31 * XXX may be obsoleted by BootFORTH or some other, better, interpreter. 32 */ 33 34#include <stand.h> 35#include <string.h> 36#include "bootstrap.h" 37 38#define MAXARGS 20 /* maximum number of arguments allowed */ 39 40static void prompt(void); 41 42/* 43 * Perform the command 44 */ 45static int 46perform(int argc, char *argv[]) 47{ 48 int i, result; 49 struct bootblk_command **cmdp; 50 bootblk_cmd_t *cmd; 51 52 if (argc < 1) 53 return(CMD_OK); 54 55 /* set return defaults; a successful command will override these */ 56 command_errmsg = command_errbuf; 57 strcpy(command_errbuf, "no error message"); 58 cmd = NULL; 59 result = CMD_ERROR; 60 61 cmdp = (struct bootblk_command **)Xcommand_set.ls_items; 62 for (i = 0; i < Xcommand_set.ls_length; i++) { 63 if ((cmdp[i]->c_name != NULL) && !strcmp(argv[0], cmdp[i]->c_name)) 64 cmd = cmdp[i]->c_fn; 65 } 66 if (cmd != NULL) { 67 result = (cmd)(argc, argv); 68 } else { 69 command_errmsg = "unknown command"; 70 } 71 return(result); 72} 73 74/* 75 * Interactive mode 76 */ 77void 78interact(void) 79{ 80 char input[256]; /* big enough? */ 81 int argc; 82 char **argv; 83 84 /* 85 * Read our default configuration 86 */ 87 source("/boot/boot.conf"); 88 printf("\n"); 89 /* 90 * Before interacting, we might want to autoboot. 91 */ 92 autoboot_maybe(); 93 94 /* 95 * Not autobooting, go manual 96 */ 97 printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 98 setenv("prompt", "${currdev}>", 1); 99 100 101 for (;;) { 102 input[0] = '\0'; 103 prompt(); 104 ngets(input, sizeof(input)); 105 if (!parse(&argc, &argv, input)) { 106 if (perform(argc, argv)) 107 printf("%s: %s\n", argv[0], command_errmsg); 108 free(argv); 109 } else { 110 printf("parse error\n"); 111 } 112 } 113} 114 115/* 116 * Read commands from a file, then execute them. 117 * 118 * We store the commands in memory and close the source file so that the media 119 * holding it can safely go away while we are executing. 120 * 121 * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so 122 * that the script won't stop if they fail). 123 */ 124COMMAND_SET(source, "source", "read commands from a file", command_source); 125 126static int 127command_source(int argc, char *argv[]) 128{ 129 int i; 130 131 for (i = 1; i < argc; i++) 132 source(argv[i]); 133 return(CMD_OK); 134} 135 136struct sourceline 137{ 138 char *text; 139 int flags; 140 int line; 141#define SL_QUIET (1<<0) 142#define SL_IGNOREERR (1<<1) 143 struct sourceline *next; 144}; 145 146void 147source(char *filename) 148{ 149 struct sourceline *script, *se, *sp; 150 char input[256]; /* big enough? */ 151 int argc; 152 char **argv, *cp; 153 int fd, flags, line; 154 155 if (((fd = open(filename, O_RDONLY)) == -1)) { 156 printf("can't open '%s': %s\n", filename, strerror(errno)); 157 return; 158 } 159 160 /* 161 * Read the script into memory. 162 */ 163 script = se = NULL; 164 line = 0; 165 166 while (fgetstr(input, sizeof(input), fd) > 0) { 167 line++; 168 flags = 0; 169 /* Discard comments */ 170 if (input[0] == '#') 171 continue; 172 cp = input; 173 /* Echo? */ 174 if (input[0] == '@') { 175 cp++; 176 flags |= SL_QUIET; 177 } 178 /* Error OK? */ 179 if (input[0] == '-') { 180 cp++; 181 flags |= SL_IGNOREERR; 182 } 183 /* Allocate script line structure and copy line, flags */ 184 sp = malloc(sizeof(struct sourceline) + strlen(cp) + 1); 185 sp->text = (char *)sp + sizeof(struct sourceline); 186 strcpy(sp->text, cp); 187 sp->flags = flags; 188 sp->line = line; 189 sp->next = NULL; 190 191 if (script == NULL) { 192 script = sp; 193 } else { 194 se->next = sp; 195 } 196 se = sp; 197 } 198 close(fd); 199 200 /* 201 * Execute the script 202 */ 203 argv = NULL; 204 for (sp = script; sp != NULL; sp = sp->next) { 205 206 /* print if not being quiet */ 207 if (!(sp->flags & SL_QUIET)) { 208 prompt(); 209 printf("%s\n", sp->text); 210 } 211 212 /* Parse the command */ 213 if (!parse(&argc, &argv, sp->text)) { 214 if ((argc > 0) && (perform(argc, argv) != 0)) { 215 /* normal command */ 216 printf("%s: %s\n", argv[0], command_errmsg); 217 if (!(sp->flags & SL_IGNOREERR)) 218 break; 219 } 220 free(argv); 221 argv = NULL; 222 } else { 223 printf("%s line %d: parse error\n", filename, sp->line); 224 break; 225 } 226 } 227 if (argv != NULL) 228 free(argv); 229 while(script != NULL) { 230 se = script; 231 script = script->next; 232 free(se); 233 } 234} 235 236/* 237 * Emit the current prompt; use the same syntax as the parser 238 * for embedding environment variables. 239 */ 240static void 241prompt(void) 242{ 243 char *p, *cp, *ev; 244 245 if ((cp = getenv("prompt")) == NULL) 246 cp = ">"; 247 p = strdup(cp); 248 249 while (*p != 0) { 250 if ((*p == '$') && (*(p+1) == '{')) { 251 for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 252 ; 253 *cp = 0; 254 ev = getenv(p + 2); 255 256 if (ev != NULL) 257 printf(ev); 258 p = cp + 1; 259 continue; 260 } 261 putchar(*p++); 262 } 263 putchar(' '); 264} 265