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: stable/11/stand/common/interp_simple.c 344413 2019-02-21 03:18:12Z kevans $");
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	/*
100	 * Read the script into memory.
101	 */
102	script = se = NULL;
103	line = 0;
104
105	while (fgetstr(input, sizeof(input), fd) >= 0) {
106		line++;
107		flags = 0;
108		/* Discard comments */
109		if (strncmp(input+strspn(input, " "), "\\ ", 2) == 0)
110			continue;
111		cp = input;
112		/* Echo? */
113		if (input[0] == '@') {
114			cp++;
115			flags |= SL_QUIET;
116		}
117		/* Error OK? */
118		if (input[0] == '-') {
119			cp++;
120			flags |= SL_IGNOREERR;
121		}
122
123		/* Allocate script line structure and copy line, flags */
124		if (*cp == '\0')
125			continue;	/* ignore empty line, save memory */
126		sp = malloc(sizeof(struct includeline) + strlen(cp) + 1);
127		/* On malloc failure (it happens!), free as much as possible and exit */
128		if (sp == NULL) {
129			while (script != NULL) {
130				se = script;
131				script = script->next;
132				free(se);
133			}
134			snprintf(command_errbuf, sizeof(command_errbuf),
135			    "file '%s' line %d: memory allocation failure - aborting",
136			    filename, line);
137			close(fd);
138			return (CMD_ERROR);
139		}
140		strcpy(sp->text, cp);
141		sp->flags = flags;
142		sp->line = line;
143		sp->next = NULL;
144
145		if (script == NULL) {
146			script = sp;
147		} else {
148			se->next = sp;
149		}
150		se = sp;
151	}
152	close(fd);
153
154	/*
155	 * Execute the script
156	 */
157	argv = NULL;
158	res = CMD_OK;
159	for (sp = script; sp != NULL; sp = sp->next) {
160
161		/* print if not being quiet */
162		if (!(sp->flags & SL_QUIET)) {
163			interp_emit_prompt();
164			printf("%s\n", sp->text);
165		}
166
167		/* Parse the command */
168		if (!parse(&argc, &argv, sp->text)) {
169			if ((argc > 0) && (interp_builtin_cmd(argc, argv) != 0)) {
170				/* normal command */
171				printf("%s: %s\n", argv[0], command_errmsg);
172				if (!(sp->flags & SL_IGNOREERR)) {
173					res=CMD_ERROR;
174					break;
175				}
176			}
177			free(argv);
178			argv = NULL;
179		} else {
180			printf("%s line %d: parse error\n", filename, sp->line);
181			res=CMD_ERROR;
182			break;
183		}
184	}
185	if (argv != NULL)
186		free(argv);
187
188	while (script != NULL) {
189		se = script;
190		script = script->next;
191		free(se);
192	}
193	return(res);
194}
195