2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/boot/common/interp.c,v 1.29 2003/08/25 23:30:41 obrien Exp $
30 * Simple commandline interpreter, toplevel and misc.
35 #include "bootstrap.h"
38 static void prompt(void);
39 static int iseol(char c
);
40 static void skipeol(int fd
);
46 perform(int argc
, char *argv
[])
49 struct bootblk_command
**cmdp
;
57 if (strchr(av0
, '=') != NULL
)
60 /* set return defaults; a successful command will override these */
61 command_errmsg
= command_errbuf
;
62 strcpy(command_errbuf
, "no error message");
66 /* search the command set for the command */
67 SET_FOREACH(cmdp
, Xcommand_set
) {
68 if (((*cmdp
)->c_name
!= NULL
) && !strcmp(av0
, (*cmdp
)->c_name
)) {
74 if ((*cmdp
)->c_cond
|| CurrentCondition
!= 0)
75 result
= (cmd
)(argc
, argv
);
79 command_errmsg
= "unknown command";
90 char input
[256]; /* big enough? */
95 * We may be booting from the boot partition, or we may be booting
96 * from the root partition with a /boot sub-directory. If the latter
97 * chdir into /boot. Ignore any error. Only rel_open() uses the chdir
101 setenv("base", DirBase
, 1);
104 * Read our default configuration
106 if (include("dloader.rc") != CMD_OK
)
107 include("boot.conf");
110 * Before interacting, we might want to autoboot.
117 * Not autobooting, go manual
119 printf("\nType '?' for a list of commands, 'help' for more detailed help.\n");
120 if (getenv("prompt") == NULL
)
121 setenv("prompt", "OK", 1);
126 ngets(input
, sizeof(input
));
127 if (!parse(&argc
, &argv
, input
)) {
128 if (perform(argc
, argv
))
129 printf("%s: %s\n", argv
[0], command_errmsg
);
132 printf("parse error\n");
138 * Read commands from a file, then execute them.
140 * We store the commands in memory and close the source file so that the media
141 * holding it can safely go away while we are executing.
143 * Commands may be prefixed with '@' (so they aren't displayed) or '-' (so
144 * that the script won't stop if they fail).
146 COMMAND_SET(include
, "include", "run commands from file", command_include
);
149 command_include(int argc
, char *argv
[])
156 * Since argv is static, we need to save it here.
158 argvbuf
= (char**) calloc((u_int
)argc
, sizeof(char*));
159 for (i
= 0; i
< argc
; i
++)
160 argvbuf
[i
] = strdup(argv
[i
]);
163 for (i
= 1; (i
< argc
) && (res
== CMD_OK
); i
++)
164 res
= include(argvbuf
[i
]);
166 for (i
= 0; i
< argc
; i
++)
173 COMMAND_SET(optinclude
, "optinclude",
174 "run commands from file; ignore exit status",
178 command_optinclude(int argc
, char *argv
[])
184 * Since argv is static, we need to save it here.
186 argvbuf
= (char**) calloc((u_int
)argc
, sizeof(char*));
187 for (i
= 0; i
< argc
; i
++)
188 argvbuf
[i
] = strdup(argv
[i
]);
190 for (i
= 1; (i
< argc
); i
++)
193 for (i
= 0; i
< argc
; i
++)
205 #define SL_QUIET (1<<0)
206 #define SL_IGNOREERR (1<<1)
207 struct includeline
*next
;
211 include(const char *filename
)
213 struct includeline
*script
, *se
, *sp
;
214 char input
[1024]; /* big enough? */
219 if (((fd
= rel_open(filename
, NULL
, O_RDONLY
)) == -1)) {
220 command_errmsg
= command_errbuf
;
221 snprintf(command_errbuf
, sizeof(command_errbuf
),
222 "cannot find \"%s\"", filename
);
227 * Read the script into memory.
232 while (fgets(input
, sizeof(input
), fd
) != NULL
) {
235 if(strlen(input
) == sizeof(input
) - 1 &&
236 !iseol(input
[sizeof(input
) - 2])) {
237 printf("WARNING: %s: %s: Line too long: truncating; have:\n",
239 printf("%s\n", input
);
242 /* Discard comments */
243 if (strncmp(input
+strspn(input
, " "), "\\ ", 2) == 0)
247 if (input
[0] == '@') {
252 if (input
[0] == '-') {
254 flags
|= SL_IGNOREERR
;
256 /* Allocate script line structure and copy line, flags */
257 sp
= malloc(sizeof(struct includeline
) + strlen(cp
) + 1);
258 sp
->text
= (char *)sp
+ sizeof(struct includeline
);
259 strcpy(sp
->text
, cp
);
264 if (script
== NULL
) {
278 for (sp
= script
; sp
!= NULL
; sp
= sp
->next
) {
281 /* print if not being quiet */
282 if (!(sp
->flags
& SL_QUIET
)) {
284 printf("%s\n", sp
->text
);
288 /* Parse the command */
289 if (!parse(&argc
, &argv
, sp
->text
)) {
290 if ((argc
> 0) && (perform(argc
, argv
) != 0)) {
292 printf("%s: %s\n", argv
[0], command_errmsg
);
293 if (!(sp
->flags
& SL_IGNOREERR
)) {
301 printf("%s line %d: parse error\n", filename
, sp
->line
);
308 while(script
!= NULL
) {
310 script
= script
->next
;
317 * Emit the current prompt; use the same syntax as the parser
318 * for embedding environment variables.
323 char *pr
, *p
, *cp
, *ev
;
325 if ((cp
= getenv("prompt")) == NULL
)
330 if ((*p
== '$') && (*(p
+1) == '{')) {
331 for (cp
= p
+ 2; (*cp
!= 0) && (*cp
!= '}'); cp
++)
350 return(c
== '\n' || c
== '\r');
358 while (read(fd
, &c
, 1) == 1) {