]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/common/interp_simple.c
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
[FreeBSD/FreeBSD.git] / stand / common / interp_simple.c
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 /*
39  * Perform the command
40  */
41 static int
42 perform(int argc, char *argv[])
43 {
44         int                             result;
45         struct bootblk_command  **cmdp;
46         bootblk_cmd_t           *cmd;
47
48         if (argc < 1)
49                 return(CMD_OK);
50
51         /* set return defaults; a successful command will override these */
52         command_errmsg = command_errbuf;
53         strcpy(command_errbuf, "no error message");
54         cmd = NULL;
55         result = CMD_ERROR;
56
57         /* search the command set for the command */
58         SET_FOREACH(cmdp, Xcommand_set) {
59                 if (((*cmdp)->c_name != NULL) && !strcmp(argv[0], (*cmdp)->c_name))
60                         cmd = (*cmdp)->c_fn;
61         }
62         if (cmd != NULL) {
63                 result = (cmd)(argc, argv);
64         } else {
65                 command_errmsg = "unknown command";
66         }
67         return(result);
68 }
69
70 void
71 interp_init(void)
72 {
73
74         /* Read our default configuration. */
75         interp_include("/boot/loader.rc");
76 }
77
78 int
79 interp_run(const char *input)
80 {
81         int             argc;
82         char            **argv;
83
84         if (parse(&argc, &argv, input)) {
85                 printf("parse error\n");
86                 return CMD_ERROR;
87         }
88
89         if (perform(argc, argv)) {
90                 printf("%s: %s\n", argv[0], command_errmsg);
91                 free(argv);
92                 return CMD_ERROR;
93         }
94         free(argv);
95         return CMD_OK;
96 }
97
98 /*
99  * Header prepended to each line. The text immediately follows the header.
100  * We try to make this short in order to save memory -- the loader has
101  * limited memory available, and some of the forth files are very long.
102  */
103 struct includeline
104 {
105         struct includeline      *next;
106         int                     flags;
107         int                     line;
108 #define SL_QUIET        (1<<0)
109 #define SL_IGNOREERR    (1<<1)
110         char                    text[0];
111 };
112
113 int
114 interp_include(const char *filename)
115 {
116         struct includeline      *script, *se, *sp;
117         char                    input[256];                     /* big enough? */
118         int                     argc,res;
119         char                    **argv, *cp;
120         int                     fd, flags, line;
121
122         if (((fd = open(filename, O_RDONLY)) == -1)) {
123                 snprintf(command_errbuf, sizeof(command_errbuf),
124                     "can't open '%s': %s", filename, strerror(errno));
125                 return(CMD_ERROR);
126         }
127
128         /*
129          * Read the script into memory.
130          */
131         script = se = NULL;
132         line = 0;
133         
134         while (fgetstr(input, sizeof(input), fd) >= 0) {
135                 line++;
136                 flags = 0;
137                 /* Discard comments */
138                 if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0)
139                         continue;
140                 cp = input;
141                 /* Echo? */
142                 if (input[0] == '@') {
143                         cp++;
144                         flags |= SL_QUIET;
145                 }
146                 /* Error OK? */
147                 if (input[0] == '-') {
148                         cp++;
149                         flags |= SL_IGNOREERR;
150                 }
151
152                 /* Allocate script line structure and copy line, flags */
153                 if (*cp == '\0')
154                         continue;       /* ignore empty line, save memory */
155                 sp = malloc(sizeof(struct includeline) + strlen(cp) + 1);
156                 /* On malloc failure (it happens!), free as much as possible and exit */
157                 if (sp == NULL) {
158                         while (script != NULL) {
159                                 se = script;
160                                 script = script->next;
161                                 free(se);
162                         }
163                         snprintf(command_errbuf, sizeof(command_errbuf),
164                             "file '%s' line %d: memory allocation failure - aborting",
165                             filename, line);
166                         close(fd);
167                         return (CMD_ERROR);
168                 }
169                 strcpy(sp->text, cp);
170                 sp->flags = flags;
171                 sp->line = line;
172                 sp->next = NULL;
173
174                 if (script == NULL) {
175                         script = sp;
176                 } else {
177                         se->next = sp;
178                 }
179                 se = sp;
180         }
181         close(fd);
182
183         /*
184          * Execute the script
185          */
186         argv = NULL;
187         res = CMD_OK;
188         for (sp = script; sp != NULL; sp = sp->next) {
189         
190                 /* print if not being quiet */
191                 if (!(sp->flags & SL_QUIET)) {
192                         interp_emit_prompt();
193                         printf("%s\n", sp->text);
194                 }
195
196                 /* Parse the command */
197                 if (!parse(&argc, &argv, sp->text)) {
198                         if ((argc > 0) && (perform(argc, argv) != 0)) {
199                                 /* normal command */
200                                 printf("%s: %s\n", argv[0], command_errmsg);
201                                 if (!(sp->flags & SL_IGNOREERR)) {
202                                         res=CMD_ERROR;
203                                         break;
204                                 }
205                         }
206                         free(argv);
207                         argv = NULL;
208                 } else {
209                         printf("%s line %d: parse error\n", filename, sp->line);
210                         res=CMD_ERROR;
211                         break;
212                 }
213         }
214         if (argv != NULL)
215                 free(argv);
216
217         while (script != NULL) {
218                 se = script;
219                 script = script->next;
220                 free(se);
221         }
222         return(res);
223 }