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