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