1 /* $NetBSD: interp.c,v 1.3 2006/07/02 17:28:11 cherry 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 40 #include "bootstrap.h" 41 42 #ifdef BOOT_FORTH 43 #include "ficl.h" 44 #define RETURN(x) stackPushINT(bf_vm->pStack,!x); return(x) 45 46 extern FICL_VM *bf_vm; 47 #else 48 #define RETURN(x) return(x) 49 #endif 50 51 #define MAXARGS 20 /* maximum number of arguments allowed */ 52 53 static void prompt(void); 54 55 #ifndef BOOT_FORTH 56 static int perform(int argc, char *argv[]); 57 58 /* 59 * Perform the command 60 */ 61 int 62 perform(int argc, char *argv[]) 63 { 64 int result; 65 struct bootblk_command *cmdp; 66 bootblk_cmd_t *cmd; 67 68 int i; 69 70 if (argc < 1) 71 return(CMD_OK); 72 73 /* set return defaults; a successful command will override these */ 74 command_errmsg = command_errbuf; 75 strcpy(command_errbuf, "no error message"); 76 cmd = NULL; 77 result = CMD_ERROR; 78 79 /* search the command set for the command */ 80 for (i = 0, cmdp = commands; (cmdp->c_name != NULL) && (cmdp->c_desc != NULL ); i++, cmdp = commands + i) { 81 if ((cmdp->c_name != NULL) && !strcmp(argv[0], cmdp->c_name)) 82 cmd = cmdp->c_fn; 83 } 84 if (cmd != NULL) { 85 result = (cmd)(argc, argv); 86 } else { 87 command_errmsg = "unknown command"; 88 } 89 RETURN(result); 90 } 91 #endif /* ! BOOT_FORTH */ 92 93 /* 94 * Interactive mode 95 */ 96 void 97 interact(void) 98 { 99 char input[256]; /* big enough? */ 100 #ifndef BOOT_FORTH 101 int argc; 102 char **argv; 103 #endif 104 105 #ifdef BOOT_FORTH 106 bf_init(); 107 #endif 108 109 /* 110 * Read our default configuration 111 */ 112 if(include("/boot/loader.rc")!=CMD_OK) 113 include("/boot/boot.conf"); 114 printf("\n"); 115 116 /* 117 * XXX: Before interacting, we might want to autoboot. 118 */ 119 120 121 /* 122 * Not autobooting, go manual 123 */ 124 printf("\nType '?' for a list of commands, 'help' for more detailed help.\n"); 125 if (getenv("prompt") == NULL) 126 setenv("prompt", "${interpret}", 1); 127 if (getenv("interpret") == NULL) 128 setenv("interpret", "OK", 1); 129 130 131 for (;;) { 132 input[0] = '\0'; 133 prompt(); 134 ngets(input, sizeof(input)); 135 #ifdef BOOT_FORTH 136 bf_vm->sourceID.i = 0; 137 bf_run(input); 138 #else 139 if (!parse(&argc, &argv, input)) { 140 if (perform(argc, argv)) 141 printf("%s: %s\n", argv[0], command_errmsg); 142 free(argv); 143 } else { 144 printf("parse error\n"); 145 } 146 #endif 147 } 148 } 149 150 /* 151 * Read commands from a file, then execute them. 152 * 153 * We store the commands in memory and close the source file so that the media 154 * holding it can safely go away while we are executing. 155 * 156 * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so 157 * that the script won't stop if they fail). 158 */ 159 160 int 161 command_include(int argc, char *argv[]) 162 { 163 int i; 164 int res; 165 char **argvbuf; 166 167 /* 168 * Since argv is static, we need to save it here. 169 */ 170 argvbuf = (char**) calloc((u_int)argc, sizeof(char*)); 171 for (i = 0; i < argc; i++) 172 argvbuf[i] = strdup(argv[i]); 173 174 res=CMD_OK; 175 for (i = 1; (i < argc) && (res == CMD_OK); i++) 176 res = include(argvbuf[i]); 177 178 for (i = 0; i < argc; i++) 179 free(argvbuf[i]); 180 free(argvbuf); 181 182 return(res); 183 } 184 185 struct includeline 186 { 187 char *text; 188 int flags; 189 int line; 190 #define SL_QUIET (1<<0) 191 #define SL_IGNOREERR (1<<1) 192 struct includeline *next; 193 }; 194 195 int 196 include(const char *filename) 197 { 198 struct includeline *script, *se, *sp; 199 char input[256]; /* big enough? */ 200 #ifdef BOOT_FORTH 201 int res; 202 char *cp; 203 int prevsrcid, fd, line; 204 #else 205 int argc,res; 206 char **argv, *cp; 207 int fd, flags, line; 208 #endif 209 210 if (((fd = open(filename, O_RDONLY)) == -1)) { 211 sprintf(command_errbuf,"can't open '%s': %s\n", filename, strerror(errno)); 212 return(CMD_ERROR); 213 } 214 215 /* 216 * Read the script into memory. 217 */ 218 script = se = NULL; 219 line = 0; 220 221 while (fgetstr(input, sizeof(input), fd) >= 0) { 222 line++; 223 #ifdef BOOT_FORTH 224 cp = input; 225 #else 226 flags = 0; 227 /* Discard comments */ 228 if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0) 229 continue; 230 cp = input; 231 /* Echo? */ 232 if (input[0] == '@') { 233 cp++; 234 flags |= SL_QUIET; 235 } 236 /* Error OK? */ 237 if (input[0] == '-') { 238 cp++; 239 flags |= SL_IGNOREERR; 240 } 241 #endif 242 /* Allocate script line structure and copy line, flags */ 243 sp = alloc(sizeof(struct includeline) + strlen(cp) + 1); 244 sp->text = (char *)sp + sizeof(struct includeline); 245 strcpy(sp->text, cp); 246 #ifndef BOOT_FORTH 247 sp->flags = flags; 248 #endif 249 sp->line = line; 250 sp->next = NULL; 251 252 if (script == NULL) { 253 script = sp; 254 } else { 255 se->next = sp; 256 } 257 se = sp; 258 } 259 close(fd); 260 261 /* 262 * Execute the script 263 */ 264 #ifndef BOOT_FORTH 265 argv = NULL; 266 #else 267 prevsrcid = bf_vm->sourceID.i; 268 bf_vm->sourceID.i = fd; 269 #endif 270 res = CMD_OK; 271 for (sp = script; sp != NULL; sp = sp->next) { 272 273 #ifdef BOOT_FORTH 274 res = bf_run(sp->text); 275 if (res != VM_OUTOFTEXT) { 276 sprintf(command_errbuf, "Error while including %s, in the line:\n%s", filename, sp->text); 277 res = CMD_ERROR; 278 break; 279 } else 280 res = CMD_OK; 281 #else 282 /* print if not being quiet */ 283 if (!(sp->flags & SL_QUIET)) { 284 prompt(); 285 printf("%s\n", sp->text); 286 } 287 288 /* Parse the command */ 289 if (!parse(&argc, &argv, sp->text)) { 290 if ((argc > 0) && (perform(argc, argv) != 0)) { 291 /* normal command */ 292 printf("%s: %s\n", argv[0], command_errmsg); 293 if (!(sp->flags & SL_IGNOREERR)) { 294 res=CMD_ERROR; 295 break; 296 } 297 } 298 free(argv); 299 argv = NULL; 300 } else { 301 printf("%s line %d: parse error\n", filename, sp->line); 302 res=CMD_ERROR; 303 break; 304 } 305 #endif 306 } 307 #ifndef BOOT_FORTH 308 if (argv != NULL) 309 free(argv); 310 #else 311 bf_vm->sourceID.i = prevsrcid; 312 #endif 313 while(script != NULL) { 314 se = script; 315 script = script->next; 316 free(se); 317 } 318 return(res); 319 } 320 321 /* 322 * Emit the current prompt; use the same syntax as the parser 323 * for embedding environment variables. 324 */ 325 static void 326 prompt(void) 327 { 328 char *pr, *p, *cp, *ev; 329 330 if ((cp = getenv("prompt")) == NULL) 331 cp = ">"; 332 pr = p = strdup(cp); 333 334 while (*p != 0) { 335 if ((*p == '$') && (*(p+1) == '{')) { 336 for (cp = p + 2; (*cp != 0) && (*cp != '}'); cp++) 337 ; 338 *cp = 0; 339 ev = getenv(p + 2); 340 341 if (ev != NULL) 342 printf("%s", ev); 343 p = cp + 1; 344 continue; 345 } 346 putchar(*p++); 347 } 348 putchar(' '); 349 free(pr); 350 } 351