1 /* $NetBSD: interp.c,v 1.5 2012/12/27 20:21:51 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 /* __FBSDID("$FreeBSD: src/sys/boot/common/interp.c,v 1.29 2003/08/25 23:30:41 obrien Exp $"); */ 31 32 /* 33 * Simple commandline interpreter, toplevel and misc. 34 * 35 * XXX may be obsoleted by BootFORTH or some other, better, interpreter. 36 */ 37 38 #include <lib/libsa/stand.h> 39 #include <lib/libsa/loadfile.h> 40 #include <lib/libkern/libkern.h> 41 42 #include "bootstrap.h" 43 44 #ifdef BOOT_FORTH 45 #include "ficl.h" 46 #define RETURN(x) stackPushINT(bf_vm->pStack,!x); return(x) 47 48 extern FICL_VM *bf_vm; 49 #else 50 #define RETURN(x) return(x) 51 #endif 52 53 #define MAXARGS 20 /* maximum number of arguments allowed */ 54 55 static void prompt(void); 56 57 #ifndef BOOT_FORTH 58 static int perform(int argc, char *argv[]); 59 60 /* 61 * Perform the command 62 */ 63 int 64 perform(int argc, char *argv[]) 65 { 66 int result; 67 struct bootblk_command *cmdp; 68 bootblk_cmd_t *cmd; 69 70 int i; 71 72 if (argc < 1) 73 return(CMD_OK); 74 75 /* set return defaults; a successful command will override these */ 76 command_errmsg = command_errbuf; 77 strcpy(command_errbuf, "no error message"); 78 cmd = NULL; 79 result = CMD_ERROR; 80 81 /* search the command set for the command */ 82 for (i = 0, cmdp = commands; (cmdp->c_name != NULL) && (cmdp->c_desc != NULL ); i++, cmdp = commands + i) { 83 if ((cmdp->c_name != NULL) && !strcmp(argv[0], cmdp->c_name)) 84 cmd = cmdp->c_fn; 85 } 86 if (cmd != NULL) { 87 result = (cmd)(argc, argv); 88 } else { 89 command_errmsg = "unknown command"; 90 } 91 RETURN(result); 92 } 93 #endif /* ! BOOT_FORTH */ 94 95 /* 96 * Interactive mode 97 */ 98 void 99 interact(void) 100 { 101 char input[256]; /* big enough? */ 102 #ifndef BOOT_FORTH 103 int argc; 104 char **argv; 105 #endif 106 107 #ifdef BOOT_FORTH 108 bf_init(); 109 #endif 110 111 /* 112 * Read our default configuration 113 */ 114 if(include("/boot/loader.rc")!=CMD_OK) 115 include("/boot/boot.conf"); 116 printf("\n"); 117 118 /* 119 * XXX: Before interacting, we might want to autoboot. 120 */ 121 122 123 /* 124 * Not autobooting, go manual 125 */ 126 printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 127 if (getenv("prompt") == NULL) 128 setenv("prompt", "${interpret}", 1); 129 if (getenv("interpret") == NULL) 130 setenv("interpret", "OK", 1); 131 132 133 for (;;) { 134 input[0] = '\0'; 135 prompt(); 136 ngets(input, sizeof(input)); 137 #ifdef BOOT_FORTH 138 bf_vm->sourceID.i = 0; 139 bf_run(input); 140 #else 141 if (!parse(&argc, &argv, input)) { 142 if (perform(argc, argv)) 143 printf("%s: %s\n", argv[0], command_errmsg); 144 free(argv); 145 } else { 146 printf("parse error\n"); 147 } 148 #endif 149 } 150 } 151 152 /* 153 * Read commands from a file, then execute them. 154 * 155 * We store the commands in memory and close the source file so that the media 156 * holding it can safely go away while we are executing. 157 * 158 * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so 159 * that the script won't stop if they fail). 160 */ 161 162 int 163 command_include(int argc, char *argv[]) 164 { 165 int i; 166 int res; 167 char **argvbuf; 168 169 /* 170 * Since argv is static, we need to save it here. 171 */ 172 argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); 173 for (i = 0; i < argc; i++) 174 argvbuf[i] = strdup(argv[i]); 175 176 res=CMD_OK; 177 for (i = 1; (i < argc) && (res == CMD_OK); i++) 178 res = include(argvbuf[i]); 179 180 for (i = 0; i < argc; i++) 181 free(argvbuf[i]); 182 free(argvbuf); 183 184 return(res); 185 } 186 187 struct includeline 188 { 189 char *text; 190 int flags; 191 int line; 192 #define SL_QUIET (1<<0) 193 #define SL_IGNOREERR (1<<1) 194 struct includeline *next; 195 }; 196 197 int 198 include(const char *filename) 199 { 200 struct includeline *script, *se, *sp; 201 char input[256]; /* big enough? */ 202 #ifdef BOOT_FORTH 203 int res; 204 char *cp; 205 int prevsrcid, fd, line; 206 #else 207 int argc,res; 208 char **argv, *cp; 209 int fd, flags, line; 210 #endif 211 212 if (((fd = open(filename, O_RDONLY)) == -1)) { 213 sprintf(command_errbuf,"can't open '%s': %s\n", filename, strerror(errno)); 214 return(CMD_ERROR); 215 } 216 217 /* 218 * Read the script into memory. 219 */ 220 script = se = NULL; 221 line = 0; 222 223 while (fgetstr(input, sizeof(input), fd) >= 0) { 224 line++; 225 #ifdef BOOT_FORTH 226 cp = input; 227 #else 228 flags = 0; 229 /* Discard comments */ 230 if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0) 231 continue; 232 cp = input; 233 /* Echo? */ 234 if (input[0] == '@') { 235 cp++; 236 flags |= SL_QUIET; 237 } 238 /* Error OK? */ 239 if (input[0] == '-') { 240 cp++; 241 flags |= SL_IGNOREERR; 242 } 243 #endif 244 /* Allocate script line structure and copy line, flags */ 245 sp = alloc(sizeof(struct includeline) + strlen(cp) + 1); 246 sp->text = (char *)sp + sizeof(struct includeline); 247 strcpy(sp->text, cp); 248 #ifndef BOOT_FORTH 249 sp->flags = flags; 250 #endif 251 sp->line = line; 252 sp->next = NULL; 253 254 if (script == NULL) { 255 script = sp; 256 } else { 257 se->next = sp; 258 } 259 se = sp; 260 } 261 close(fd); 262 263 /* 264 * Execute the script 265 */ 266 #ifndef BOOT_FORTH 267 argv = NULL; 268 #else 269 prevsrcid = bf_vm->sourceID.i; 270 bf_vm->sourceID.i = fd; 271 #endif 272 res = CMD_OK; 273 for (sp = script; sp != NULL; sp = sp->next) { 274 275 #ifdef BOOT_FORTH 276 res = bf_run(sp->text); 277 if (res != VM_OUTOFTEXT) { 278 sprintf(command_errbuf, "Error while including %s, in the line:\n%s", filename, sp->text); 279 res = CMD_ERROR; 280 break; 281 } else 282 res = CMD_OK; 283 #else 284 /* print if not being quiet */ 285 if (!(sp->flags & SL_QUIET)) { 286 prompt(); 287 printf("%s\n", sp->text); 288 } 289 290 /* Parse the command */ 291 if (!parse(&argc, &argv, sp->text)) { 292 if ((argc > 0) && (perform(argc, argv) != 0)) { 293 /* normal command */ 294 printf("%s: %s\n", argv[0], command_errmsg); 295 if (!(sp->flags & SL_IGNOREERR)) { 296 res=CMD_ERROR; 297 break; 298 } 299 } 300 free(argv); 301 argv = NULL; 302 } else { 303 printf("%s line %d: parse error\n", filename, sp->line); 304 res=CMD_ERROR; 305 break; 306 } 307 #endif 308 } 309 #ifndef BOOT_FORTH 310 if (argv != NULL) 311 free(argv); 312 #else 313 bf_vm->sourceID.i = prevsrcid; 314 #endif 315 while(script != NULL) { 316 se = script; 317 script = script->next; 318 free(se); 319 } 320 return(res); 321 } 322 323 /* 324 * Emit the current prompt; use the same syntax as the parser 325 * for embedding environment variables. 326 */ 327 static void 328 prompt(void) 329 { 330 char *pr, *p, *cp, *ev; 331 332 if ((cp = getenv("prompt")) == NULL) 333 cp = ">"; 334 pr = p = strdup(cp); 335 336 while (*p != 0) { 337 if ((*p == '$') && (*(p+1) == '{')) { 338 for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 339 ; 340 *cp = 0; 341 ev = getenv(p + 2); 342 343 if (ev != NULL) 344 printf("%s", ev); 345 p = cp + 1; 346 continue; 347 } 348 putchar(*p++); 349 } 350 putchar(' '); 351 free(pr); 352 } 353