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
38INTERP_DEFINE("simp");
39
40void
41interp_init(void)
42{
43
44	setenv("script.lang", "simple", 1);
45	/* Read our default configuration. */
46	interp_include("/boot/loader.rc");
47}
48
49int
50interp_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 */
74struct 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
84int
85interp_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