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