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 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 /* 31 * Simple commandline interpreter, toplevel and misc. 32 */ 33 34 #include <stand.h> 35 #include <string.h> 36 #include "bootstrap.h" 37 38 INTERP_DEFINE("simp"); 39 40 void 41 interp_init(void) 42 { 43 44 setenv("script.lang", "simple", 1); 45 /* Read our default configuration. */ 46 interp_include("/boot/loader.rc"); 47 } 48 49 int 50 interp_run(const char *input) 51 { 52 int argc; 53 char **argv; 54 55 if (parse(&argc, &argv, input)) { 56 printf("parse error\n"); 57 return CMD_ERROR; 58 } 59 60 if (interp_builtin_cmd(argc, argv)) { 61 printf("%s: %s\n", argv[0], command_errmsg); 62 free(argv); 63 return CMD_ERROR; 64 } 65 free(argv); 66 return CMD_OK; 67 } 68 69 /* 70 * Header prepended to each line. The text immediately follows the header. 71 * We try to make this short in order to save memory -- the loader has 72 * limited memory available, and some of the forth files are very long. 73 */ 74 struct includeline 75 { 76 struct includeline *next; 77 int flags; 78 int line; 79 #define SL_QUIET (1<<0) 80 #define SL_IGNOREERR (1<<1) 81 char text[0]; 82 }; 83 84 int 85 interp_include(const char *filename) 86 { 87 struct includeline *script, *se, *sp; 88 char input[256]; /* big enough? */ 89 int argc,res; 90 char **argv, *cp; 91 int fd, flags, line; 92 93 if (((fd = open(filename, O_RDONLY)) == -1)) { 94 snprintf(command_errbuf, sizeof(command_errbuf), 95 "can't open '%s': %s", filename, strerror(errno)); 96 return(CMD_ERROR); 97 } 98 99 #ifdef LOADER_VERIEXEC 100 if (verify_file(fd, filename, 0, VE_GUESS, __func__) < 0) { 101 close(fd); 102 sprintf(command_errbuf,"can't verify '%s'", filename); 103 return(CMD_ERROR); 104 } 105 #endif 106 107 /* 108 * Read the script into memory. 109 */ 110 script = se = NULL; 111 line = 0; 112 113 while (fgetstr(input, sizeof(input), fd) >= 0) { 114 line++; 115 flags = 0; 116 /* Discard comments */ 117 if (strncmp(input+strspn(input, " "), "\\", 1) == 0) 118 continue; 119 cp = input; 120 /* Echo? */ 121 if (input[0] == '@') { 122 cp++; 123 flags |= SL_QUIET; 124 } 125 /* Error OK? */ 126 if (input[0] == '-') { 127 cp++; 128 flags |= SL_IGNOREERR; 129 } 130 131 /* Allocate script line structure and copy line, flags */ 132 if (*cp == '\0') 133 continue; /* ignore empty line, save memory */ 134 sp = malloc(sizeof(struct includeline) + strlen(cp) + 1); 135 /* On malloc failure (it happens!), free as much as possible and exit */ 136 if (sp == NULL) { 137 while (script != NULL) { 138 se = script; 139 script = script->next; 140 free(se); 141 } 142 snprintf(command_errbuf, sizeof(command_errbuf), 143 "file '%s' line %d: memory allocation failure - aborting", 144 filename, line); 145 close(fd); 146 return (CMD_ERROR); 147 } 148 strcpy(sp->text, cp); 149 sp->flags = flags; 150 sp->line = line; 151 sp->next = NULL; 152 153 if (script == NULL) { 154 script = sp; 155 } else { 156 se->next = sp; 157 } 158 se = sp; 159 } 160 close(fd); 161 162 /* 163 * Execute the script 164 */ 165 argv = NULL; 166 res = CMD_OK; 167 for (sp = script; sp != NULL; sp = sp->next) { 168 169 /* print if not being quiet */ 170 if (!(sp->flags & SL_QUIET)) { 171 interp_emit_prompt(); 172 printf("%s\n", sp->text); 173 } 174 175 /* Parse the command */ 176 if (!parse(&argc, &argv, sp->text)) { 177 if ((argc > 0) && (interp_builtin_cmd(argc, argv) != 0)) { 178 /* normal command */ 179 printf("%s: %s\n", argv[0], command_errmsg); 180 if (!(sp->flags & SL_IGNOREERR)) { 181 res=CMD_ERROR; 182 break; 183 } 184 } 185 free(argv); 186 argv = NULL; 187 } else { 188 printf("%s line %d: parse error\n", filename, sp->line); 189 res=CMD_ERROR; 190 break; 191 } 192 } 193 if (argv != NULL) 194 free(argv); 195 196 while (script != NULL) { 197 se = script; 198 script = script->next; 199 free(se); 200 } 201 return(res); 202 } 203