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