1a1bf3f78SToomas Soome /*
2a1bf3f78SToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3a1bf3f78SToomas Soome * All rights reserved.
4a1bf3f78SToomas Soome *
5a1bf3f78SToomas Soome * Redistribution and use in source and binary forms, with or without
6a1bf3f78SToomas Soome * modification, are permitted provided that the following conditions
7a1bf3f78SToomas Soome * are met:
8a1bf3f78SToomas Soome * 1. Redistributions of source code must retain the above copyright
9a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer.
10a1bf3f78SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
11a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer in the
12a1bf3f78SToomas Soome * documentation and/or other materials provided with the distribution.
13a1bf3f78SToomas Soome *
14a1bf3f78SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a1bf3f78SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a1bf3f78SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a1bf3f78SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a1bf3f78SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a1bf3f78SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a1bf3f78SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a1bf3f78SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a1bf3f78SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a1bf3f78SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a1bf3f78SToomas Soome * SUCH DAMAGE.
25a1bf3f78SToomas Soome */
26a1bf3f78SToomas Soome
27a1bf3f78SToomas Soome #include <sys/types.h>
28a1bf3f78SToomas Soome #include <sys/stat.h>
29a1bf3f78SToomas Soome #include <fcntl.h>
30a1bf3f78SToomas Soome #include <errno.h>
31a1bf3f78SToomas Soome #include <stdlib.h>
32a1bf3f78SToomas Soome #include <stdio.h>
33a1bf3f78SToomas Soome #include <string.h>
34a1bf3f78SToomas Soome #include <strings.h>
35a1bf3f78SToomas Soome #include <limits.h>
36a1bf3f78SToomas Soome #include <unistd.h>
37a1bf3f78SToomas Soome #include <dirent.h>
38a1bf3f78SToomas Soome #include <macros.h>
39a1bf3f78SToomas Soome #include <sys/systeminfo.h>
40a1bf3f78SToomas Soome #include <sys/queue.h>
41a1bf3f78SToomas Soome #include <sys/mnttab.h>
42a1bf3f78SToomas Soome #include "ficl.h"
43a1bf3f78SToomas Soome
44a1bf3f78SToomas Soome /* Commands and return values; nonzero return sets command_errmsg != NULL */
45a1bf3f78SToomas Soome typedef int (bootblk_cmd_t)(int argc, char *argv[]);
46a1bf3f78SToomas Soome #define CMD_OK 0
47a1bf3f78SToomas Soome #define CMD_ERROR 1
48a1bf3f78SToomas Soome
49a1bf3f78SToomas Soome /*
50a1bf3f78SToomas Soome * Support for commands
51a1bf3f78SToomas Soome */
52a1bf3f78SToomas Soome struct bootblk_command
53a1bf3f78SToomas Soome {
54a1bf3f78SToomas Soome const char *c_name;
55a1bf3f78SToomas Soome const char *c_desc;
56a1bf3f78SToomas Soome bootblk_cmd_t *c_fn;
57a1bf3f78SToomas Soome STAILQ_ENTRY(bootblk_command) next;
58a1bf3f78SToomas Soome };
59a1bf3f78SToomas Soome
60a1bf3f78SToomas Soome #define MDIR_REMOVED 0x0001
61a1bf3f78SToomas Soome #define MDIR_NOHINTS 0x0002
62a1bf3f78SToomas Soome
63a1bf3f78SToomas Soome struct moduledir {
64a1bf3f78SToomas Soome char *d_path; /* path of modules directory */
65a1bf3f78SToomas Soome uchar_t *d_hints; /* content of linker.hints file */
66a1bf3f78SToomas Soome int d_hintsz; /* size of hints data */
67a1bf3f78SToomas Soome int d_flags;
68a1bf3f78SToomas Soome STAILQ_ENTRY(moduledir) d_link;
69a1bf3f78SToomas Soome };
70a1bf3f78SToomas Soome static STAILQ_HEAD(, moduledir) moduledir_list =
71a1bf3f78SToomas Soome STAILQ_HEAD_INITIALIZER(moduledir_list);
72a1bf3f78SToomas Soome
73a1bf3f78SToomas Soome static const char *default_searchpath = "/platform/i86pc";
74a1bf3f78SToomas Soome
75a1bf3f78SToomas Soome static char typestr[] = "?fc?d?b? ?l?s?w";
76a1bf3f78SToomas Soome static int ls_getdir(char **pathp);
77a1bf3f78SToomas Soome extern char **_environ;
78a1bf3f78SToomas Soome
79a1bf3f78SToomas Soome char *command_errmsg;
80a1bf3f78SToomas Soome char command_errbuf[256];
81a1bf3f78SToomas Soome
82a1bf3f78SToomas Soome extern void pager_open(void);
83a1bf3f78SToomas Soome extern void pager_close(void);
84a1bf3f78SToomas Soome extern int pager_output(const char *);
85a1bf3f78SToomas Soome extern int pager_file(const char *);
86a1bf3f78SToomas Soome static int page_file(char *);
87a1bf3f78SToomas Soome static int include(const char *);
88a1bf3f78SToomas Soome
89a1bf3f78SToomas Soome static int command_help(int argc, char *argv[]);
90a1bf3f78SToomas Soome static int command_commandlist(int argc, char *argv[]);
91a1bf3f78SToomas Soome static int command_show(int argc, char *argv[]);
92a1bf3f78SToomas Soome static int command_set(int argc, char *argv[]);
93a1bf3f78SToomas Soome static int command_setprop(int argc, char *argv[]);
94a1bf3f78SToomas Soome static int command_unset(int argc, char *argv[]);
95a1bf3f78SToomas Soome static int command_echo(int argc, char *argv[]);
96a1bf3f78SToomas Soome static int command_read(int argc, char *argv[]);
97a1bf3f78SToomas Soome static int command_more(int argc, char *argv[]);
98a1bf3f78SToomas Soome static int command_ls(int argc, char *argv[]);
99a1bf3f78SToomas Soome static int command_include(int argc, char *argv[]);
100a1bf3f78SToomas Soome static int command_autoboot(int argc, char *argv[]);
101a1bf3f78SToomas Soome static int command_boot(int argc, char *argv[]);
102a1bf3f78SToomas Soome static int command_unload(int argc, char *argv[]);
103a1bf3f78SToomas Soome static int command_load(int argc, char *argv[]);
104a1bf3f78SToomas Soome static int command_reboot(int argc, char *argv[]);
105a1bf3f78SToomas Soome
106a1bf3f78SToomas Soome #define BF_PARSE 100
107a1bf3f78SToomas Soome #define BF_DICTSIZE 30000
108a1bf3f78SToomas Soome
109a1bf3f78SToomas Soome /* update when loader version will change */
110a1bf3f78SToomas Soome static const char bootprog_rev[] = "1.1";
111a1bf3f78SToomas Soome STAILQ_HEAD(cmdh, bootblk_command) commands;
112a1bf3f78SToomas Soome
113a1bf3f78SToomas Soome /*
114a1bf3f78SToomas Soome * BootForth Interface to Ficl Forth interpreter.
115a1bf3f78SToomas Soome */
116a1bf3f78SToomas Soome
117a1bf3f78SToomas Soome ficlSystem *bf_sys;
118a1bf3f78SToomas Soome ficlVm *bf_vm;
119a1bf3f78SToomas Soome
120a1bf3f78SToomas Soome /*
121a1bf3f78SToomas Soome * Redistribution and use in source and binary forms, with or without
122a1bf3f78SToomas Soome * modification, are permitted provided that the following conditions
123a1bf3f78SToomas Soome * are met:
124a1bf3f78SToomas Soome * 1. Redistributions of source code must retain the above copyright
125a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer.
126a1bf3f78SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
127a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer in the
128a1bf3f78SToomas Soome * documentation and/or other materials provided with the distribution.
129a1bf3f78SToomas Soome *
130a1bf3f78SToomas Soome * Jordan K. Hubbard
131a1bf3f78SToomas Soome * 29 August 1998
132a1bf3f78SToomas Soome *
133a1bf3f78SToomas Soome * The meat of the simple parser.
134a1bf3f78SToomas Soome */
135a1bf3f78SToomas Soome
136a1bf3f78SToomas Soome static void clean(void);
137a1bf3f78SToomas Soome static int insert(int *argcp, char *buf);
138a1bf3f78SToomas Soome
139a1bf3f78SToomas Soome #define PARSE_BUFSIZE 1024 /* maximum size of one element */
140a1bf3f78SToomas Soome #define MAXARGS 20 /* maximum number of elements */
141a1bf3f78SToomas Soome static char *args[MAXARGS];
142a1bf3f78SToomas Soome
143a1bf3f78SToomas Soome #define DIGIT(x) \
144a1bf3f78SToomas Soome (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
145a1bf3f78SToomas Soome
146a1bf3f78SToomas Soome /*
147a1bf3f78SToomas Soome * backslash: Return malloc'd copy of str with all standard "backslash
148a1bf3f78SToomas Soome * processing" done on it. Original can be free'd if desired.
149a1bf3f78SToomas Soome */
150a1bf3f78SToomas Soome char *
backslash(char * str)151a1bf3f78SToomas Soome backslash(char *str)
152a1bf3f78SToomas Soome {
153a1bf3f78SToomas Soome /*
154a1bf3f78SToomas Soome * Remove backslashes from the strings. Turn \040 etc. into a single
155a1bf3f78SToomas Soome * character (we allow eight bit values). Currently NUL is not
156a1bf3f78SToomas Soome * allowed.
157a1bf3f78SToomas Soome *
158a1bf3f78SToomas Soome * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
159a1bf3f78SToomas Soome */
160a1bf3f78SToomas Soome char *new_str;
161a1bf3f78SToomas Soome int seenbs = 0;
162a1bf3f78SToomas Soome int i = 0;
163a1bf3f78SToomas Soome
164a1bf3f78SToomas Soome if ((new_str = strdup(str)) == NULL)
165a1bf3f78SToomas Soome return (NULL);
166a1bf3f78SToomas Soome
167a1bf3f78SToomas Soome while (*str) {
168a1bf3f78SToomas Soome if (seenbs) {
169a1bf3f78SToomas Soome seenbs = 0;
170a1bf3f78SToomas Soome switch (*str) {
171a1bf3f78SToomas Soome case '\\':
172a1bf3f78SToomas Soome new_str[i++] = '\\';
173a1bf3f78SToomas Soome str++;
174a1bf3f78SToomas Soome break;
175a1bf3f78SToomas Soome
176a1bf3f78SToomas Soome /* preserve backslashed quotes, dollar signs */
177a1bf3f78SToomas Soome case '\'':
178a1bf3f78SToomas Soome case '"':
179a1bf3f78SToomas Soome case '$':
180a1bf3f78SToomas Soome new_str[i++] = '\\';
181a1bf3f78SToomas Soome new_str[i++] = *str++;
182a1bf3f78SToomas Soome break;
183a1bf3f78SToomas Soome
184a1bf3f78SToomas Soome case 'b':
185a1bf3f78SToomas Soome new_str[i++] = '\b';
186a1bf3f78SToomas Soome str++;
187a1bf3f78SToomas Soome break;
188a1bf3f78SToomas Soome
189a1bf3f78SToomas Soome case 'f':
190a1bf3f78SToomas Soome new_str[i++] = '\f';
191a1bf3f78SToomas Soome str++;
192a1bf3f78SToomas Soome break;
193a1bf3f78SToomas Soome
194a1bf3f78SToomas Soome case 'r':
195a1bf3f78SToomas Soome new_str[i++] = '\r';
196a1bf3f78SToomas Soome str++;
197a1bf3f78SToomas Soome break;
198a1bf3f78SToomas Soome
199a1bf3f78SToomas Soome case 'n':
200a1bf3f78SToomas Soome new_str[i++] = '\n';
201a1bf3f78SToomas Soome str++;
202a1bf3f78SToomas Soome break;
203a1bf3f78SToomas Soome
204a1bf3f78SToomas Soome case 's':
205a1bf3f78SToomas Soome new_str[i++] = ' ';
206a1bf3f78SToomas Soome str++;
207a1bf3f78SToomas Soome break;
208a1bf3f78SToomas Soome
209a1bf3f78SToomas Soome case 't':
210a1bf3f78SToomas Soome new_str[i++] = '\t';
211a1bf3f78SToomas Soome str++;
212a1bf3f78SToomas Soome break;
213a1bf3f78SToomas Soome
214a1bf3f78SToomas Soome case 'v':
215a1bf3f78SToomas Soome new_str[i++] = '\13';
216a1bf3f78SToomas Soome str++;
217a1bf3f78SToomas Soome break;
218a1bf3f78SToomas Soome
219a1bf3f78SToomas Soome case 'z':
220a1bf3f78SToomas Soome str++;
221a1bf3f78SToomas Soome break;
222a1bf3f78SToomas Soome
223a1bf3f78SToomas Soome case '0': case '1': case '2': case '3': case '4':
224a1bf3f78SToomas Soome case '5': case '6': case '7': case '8': case '9': {
225a1bf3f78SToomas Soome char val;
226a1bf3f78SToomas Soome
227a1bf3f78SToomas Soome /* Three digit octal constant? */
228a1bf3f78SToomas Soome if (*str >= '0' && *str <= '3' &&
229a1bf3f78SToomas Soome *(str + 1) >= '0' && *(str + 1) <= '7' &&
230a1bf3f78SToomas Soome *(str + 2) >= '0' && *(str + 2) <= '7') {
231a1bf3f78SToomas Soome
232a1bf3f78SToomas Soome val = (DIGIT(*str) << 6) +
233a1bf3f78SToomas Soome (DIGIT(*(str + 1)) << 3) +
234a1bf3f78SToomas Soome DIGIT(*(str + 2));
235a1bf3f78SToomas Soome
236a1bf3f78SToomas Soome /*
237a1bf3f78SToomas Soome * Allow null value if user really
238a1bf3f78SToomas Soome * wants to shoot at feet, but beware!
239a1bf3f78SToomas Soome */
240a1bf3f78SToomas Soome new_str[i++] = val;
241a1bf3f78SToomas Soome str += 3;
242a1bf3f78SToomas Soome break;
243a1bf3f78SToomas Soome }
244a1bf3f78SToomas Soome
245a1bf3f78SToomas Soome /*
246a1bf3f78SToomas Soome * One or two digit hex constant?
247a1bf3f78SToomas Soome * If two are there they will both be taken.
248a1bf3f78SToomas Soome * Use \z to split them up if this is not
249a1bf3f78SToomas Soome * wanted.
250a1bf3f78SToomas Soome */
251a1bf3f78SToomas Soome if (*str == '0' &&
252a1bf3f78SToomas Soome (*(str + 1) == 'x' || *(str + 1) == 'X') &&
253a1bf3f78SToomas Soome isxdigit(*(str + 2))) {
254a1bf3f78SToomas Soome val = DIGIT(*(str + 2));
255a1bf3f78SToomas Soome if (isxdigit(*(str + 3))) {
256a1bf3f78SToomas Soome val = (val << 4) +
257a1bf3f78SToomas Soome DIGIT(*(str + 3));
258a1bf3f78SToomas Soome str += 4;
259a1bf3f78SToomas Soome } else
260a1bf3f78SToomas Soome str += 3;
261a1bf3f78SToomas Soome /* Yep, allow null value here too */
262a1bf3f78SToomas Soome new_str[i++] = val;
263a1bf3f78SToomas Soome break;
264a1bf3f78SToomas Soome }
265a1bf3f78SToomas Soome }
266a1bf3f78SToomas Soome break;
267a1bf3f78SToomas Soome
268a1bf3f78SToomas Soome default:
269a1bf3f78SToomas Soome new_str[i++] = *str++;
270a1bf3f78SToomas Soome break;
271a1bf3f78SToomas Soome }
272a1bf3f78SToomas Soome } else {
273a1bf3f78SToomas Soome if (*str == '\\') {
274a1bf3f78SToomas Soome seenbs = 1;
275a1bf3f78SToomas Soome str++;
276a1bf3f78SToomas Soome } else
277a1bf3f78SToomas Soome new_str[i++] = *str++;
278a1bf3f78SToomas Soome }
279a1bf3f78SToomas Soome }
280a1bf3f78SToomas Soome
281a1bf3f78SToomas Soome if (seenbs) {
282a1bf3f78SToomas Soome /*
283a1bf3f78SToomas Soome * The final character was a '\'.
284a1bf3f78SToomas Soome * Put it in as a single backslash.
285a1bf3f78SToomas Soome */
286a1bf3f78SToomas Soome new_str[i++] = '\\';
287a1bf3f78SToomas Soome }
288a1bf3f78SToomas Soome new_str[i] = '\0';
289a1bf3f78SToomas Soome return (new_str);
290a1bf3f78SToomas Soome }
291a1bf3f78SToomas Soome
292a1bf3f78SToomas Soome /*
293a1bf3f78SToomas Soome * parse: accept a string of input and "parse" it for backslash
294a1bf3f78SToomas Soome * substitutions and environment variable expansions (${var}),
295a1bf3f78SToomas Soome * returning an argc/argv style vector of whitespace separated
296a1bf3f78SToomas Soome * arguments. Returns 0 on success, 1 on failure (ok, ok, so I
297a1bf3f78SToomas Soome * wimped-out on the error codes! :).
298a1bf3f78SToomas Soome *
299a1bf3f78SToomas Soome * Note that the argv array returned must be freed by the caller, but
300a1bf3f78SToomas Soome * we own the space allocated for arguments and will free that on next
301a1bf3f78SToomas Soome * invocation. This allows argv consumers to modify the array if
302a1bf3f78SToomas Soome * required.
303a1bf3f78SToomas Soome *
304a1bf3f78SToomas Soome * NB: environment variables that expand to more than one whitespace
305a1bf3f78SToomas Soome * separated token will be returned as a single argv[] element, not
306a1bf3f78SToomas Soome * split in turn. Expanded text is also immune to further backslash
307a1bf3f78SToomas Soome * elimination or expansion since this is a one-pass, non-recursive
308a1bf3f78SToomas Soome * parser. You didn't specify more than this so if you want more, ask
309a1bf3f78SToomas Soome * me. - jkh
310a1bf3f78SToomas Soome */
311a1bf3f78SToomas Soome
312a1bf3f78SToomas Soome #define PARSE_FAIL(expr) \
313a1bf3f78SToomas Soome if (expr) { \
314a1bf3f78SToomas Soome printf("fail at line %d\n", __LINE__); \
315a1bf3f78SToomas Soome clean(); \
316a1bf3f78SToomas Soome free(copy); \
317a1bf3f78SToomas Soome free(buf); \
318a1bf3f78SToomas Soome return (1); \
319a1bf3f78SToomas Soome }
320a1bf3f78SToomas Soome
321a1bf3f78SToomas Soome /* Accept the usual delimiters for a variable, returning counterpart */
322a1bf3f78SToomas Soome static char
isdelim(int ch)323a1bf3f78SToomas Soome isdelim(int ch)
324a1bf3f78SToomas Soome {
325a1bf3f78SToomas Soome if (ch == '{')
326a1bf3f78SToomas Soome return ('}');
327a1bf3f78SToomas Soome else if (ch == '(')
328a1bf3f78SToomas Soome return (')');
329a1bf3f78SToomas Soome return ('\0');
330a1bf3f78SToomas Soome }
331a1bf3f78SToomas Soome
332a1bf3f78SToomas Soome static int
isquote(int ch)333a1bf3f78SToomas Soome isquote(int ch)
334a1bf3f78SToomas Soome {
335a1bf3f78SToomas Soome return (ch == '\'');
336a1bf3f78SToomas Soome }
337a1bf3f78SToomas Soome
338a1bf3f78SToomas Soome static int
isdquote(int ch)339a1bf3f78SToomas Soome isdquote(int ch)
340a1bf3f78SToomas Soome {
341a1bf3f78SToomas Soome return (ch == '"');
342a1bf3f78SToomas Soome }
343a1bf3f78SToomas Soome
344a1bf3f78SToomas Soome int
parse(int * argc,char *** argv,char * str)345a1bf3f78SToomas Soome parse(int *argc, char ***argv, char *str)
346a1bf3f78SToomas Soome {
347a1bf3f78SToomas Soome int ac;
348a1bf3f78SToomas Soome char *val, *p, *q, *copy = NULL;
349a1bf3f78SToomas Soome size_t i = 0;
350a1bf3f78SToomas Soome char token, tmp, quote, dquote, *buf;
351a1bf3f78SToomas Soome enum { STR, VAR, WHITE } state;
352a1bf3f78SToomas Soome
353a1bf3f78SToomas Soome ac = *argc = 0;
354a1bf3f78SToomas Soome dquote = quote = 0;
355a1bf3f78SToomas Soome if (!str || (p = copy = backslash(str)) == NULL)
356a1bf3f78SToomas Soome return (1);
357a1bf3f78SToomas Soome
358a1bf3f78SToomas Soome /* Initialize vector and state */
359a1bf3f78SToomas Soome clean();
360a1bf3f78SToomas Soome state = STR;
361a1bf3f78SToomas Soome buf = (char *)malloc(PARSE_BUFSIZE);
362a1bf3f78SToomas Soome token = 0;
363a1bf3f78SToomas Soome
364a1bf3f78SToomas Soome /* And awaaaaaaaaay we go! */
365a1bf3f78SToomas Soome while (*p) {
366a1bf3f78SToomas Soome switch (state) {
367a1bf3f78SToomas Soome case STR:
368a1bf3f78SToomas Soome if ((*p == '\\') && p[1]) {
369a1bf3f78SToomas Soome p++;
370a1bf3f78SToomas Soome PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
371a1bf3f78SToomas Soome buf[i++] = *p++;
372a1bf3f78SToomas Soome } else if (isquote(*p)) {
373a1bf3f78SToomas Soome quote = quote ? 0 : *p;
374a1bf3f78SToomas Soome if (dquote) { /* keep quote */
375a1bf3f78SToomas Soome PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
376a1bf3f78SToomas Soome buf[i++] = *p++;
377a1bf3f78SToomas Soome } else
378a1bf3f78SToomas Soome ++p;
379a1bf3f78SToomas Soome } else if (isdquote(*p)) {
380a1bf3f78SToomas Soome dquote = dquote ? 0 : *p;
381a1bf3f78SToomas Soome if (quote) { /* keep dquote */
382a1bf3f78SToomas Soome PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
383a1bf3f78SToomas Soome buf[i++] = *p++;
384a1bf3f78SToomas Soome } else
385a1bf3f78SToomas Soome ++p;
386a1bf3f78SToomas Soome } else if (isspace(*p) && !quote && !dquote) {
387a1bf3f78SToomas Soome state = WHITE;
388a1bf3f78SToomas Soome if (i) {
389a1bf3f78SToomas Soome buf[i] = '\0';
390a1bf3f78SToomas Soome PARSE_FAIL(insert(&ac, buf));
391a1bf3f78SToomas Soome i = 0;
392a1bf3f78SToomas Soome }
393a1bf3f78SToomas Soome ++p;
394a1bf3f78SToomas Soome } else if (*p == '$' && !quote) {
395a1bf3f78SToomas Soome token = isdelim(*(p + 1));
396a1bf3f78SToomas Soome if (token)
397a1bf3f78SToomas Soome p += 2;
398a1bf3f78SToomas Soome else
399a1bf3f78SToomas Soome ++p;
400a1bf3f78SToomas Soome state = VAR;
401a1bf3f78SToomas Soome } else {
402a1bf3f78SToomas Soome PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
403a1bf3f78SToomas Soome buf[i++] = *p++;
404a1bf3f78SToomas Soome }
405a1bf3f78SToomas Soome break;
406a1bf3f78SToomas Soome
407a1bf3f78SToomas Soome case WHITE:
408a1bf3f78SToomas Soome if (isspace(*p))
409a1bf3f78SToomas Soome ++p;
410a1bf3f78SToomas Soome else
411a1bf3f78SToomas Soome state = STR;
412a1bf3f78SToomas Soome break;
413a1bf3f78SToomas Soome
414a1bf3f78SToomas Soome case VAR:
415a1bf3f78SToomas Soome if (token) {
416a1bf3f78SToomas Soome PARSE_FAIL((q = strchr(p, token)) == NULL);
417a1bf3f78SToomas Soome } else {
418a1bf3f78SToomas Soome q = p;
419a1bf3f78SToomas Soome while (*q && !isspace(*q))
420a1bf3f78SToomas Soome ++q;
421a1bf3f78SToomas Soome }
422a1bf3f78SToomas Soome tmp = *q;
423a1bf3f78SToomas Soome *q = '\0';
424a1bf3f78SToomas Soome if ((val = getenv(p)) != NULL) {
425a1bf3f78SToomas Soome size_t len = strlen(val);
426a1bf3f78SToomas Soome
427a1bf3f78SToomas Soome strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1));
428a1bf3f78SToomas Soome i += min(len, PARSE_BUFSIZE - 1);
429a1bf3f78SToomas Soome }
430a1bf3f78SToomas Soome *q = tmp; /* restore value */
431a1bf3f78SToomas Soome p = q + (token ? 1 : 0);
432a1bf3f78SToomas Soome state = STR;
433a1bf3f78SToomas Soome break;
434a1bf3f78SToomas Soome }
435a1bf3f78SToomas Soome }
436a1bf3f78SToomas Soome /* missing terminating ' or " */
437a1bf3f78SToomas Soome PARSE_FAIL(quote || dquote);
438a1bf3f78SToomas Soome /* If at end of token, add it */
439a1bf3f78SToomas Soome if (i && state == STR) {
440a1bf3f78SToomas Soome buf[i] = '\0';
441a1bf3f78SToomas Soome PARSE_FAIL(insert(&ac, buf));
442a1bf3f78SToomas Soome }
443a1bf3f78SToomas Soome args[ac] = NULL;
444a1bf3f78SToomas Soome *argc = ac;
445a1bf3f78SToomas Soome *argv = (char **)malloc((sizeof (char *) * ac + 1));
446a1bf3f78SToomas Soome bcopy(args, *argv, sizeof (char *) * ac + 1);
447a1bf3f78SToomas Soome free(buf);
448a1bf3f78SToomas Soome free(copy);
449a1bf3f78SToomas Soome return (0);
450a1bf3f78SToomas Soome }
451a1bf3f78SToomas Soome
452a1bf3f78SToomas Soome #define MAXARGS 20
453a1bf3f78SToomas Soome
454a1bf3f78SToomas Soome /* Clean vector space */
455a1bf3f78SToomas Soome static void
clean(void)456a1bf3f78SToomas Soome clean(void)
457a1bf3f78SToomas Soome {
458a1bf3f78SToomas Soome int i;
459a1bf3f78SToomas Soome
460a1bf3f78SToomas Soome for (i = 0; i < MAXARGS; i++) {
461a1bf3f78SToomas Soome if (args[i] != NULL) {
462a1bf3f78SToomas Soome free(args[i]);
463a1bf3f78SToomas Soome args[i] = NULL;
464a1bf3f78SToomas Soome }
465a1bf3f78SToomas Soome }
466a1bf3f78SToomas Soome }
467a1bf3f78SToomas Soome
468a1bf3f78SToomas Soome static int
insert(int * argcp,char * buf)469a1bf3f78SToomas Soome insert(int *argcp, char *buf)
470a1bf3f78SToomas Soome {
471a1bf3f78SToomas Soome if (*argcp >= MAXARGS)
472a1bf3f78SToomas Soome return (1);
473a1bf3f78SToomas Soome args[(*argcp)++] = strdup(buf);
474a1bf3f78SToomas Soome return (0);
475a1bf3f78SToomas Soome }
476a1bf3f78SToomas Soome
477a1bf3f78SToomas Soome static char *
isadir(void)478a1bf3f78SToomas Soome isadir(void)
479a1bf3f78SToomas Soome {
480a1bf3f78SToomas Soome char *buf;
481a1bf3f78SToomas Soome size_t bufsize = 20;
482a1bf3f78SToomas Soome int ret;
483a1bf3f78SToomas Soome
484a1bf3f78SToomas Soome if ((buf = malloc(bufsize)) == NULL)
485a1bf3f78SToomas Soome return (NULL);
486a1bf3f78SToomas Soome ret = sysinfo(SI_ARCHITECTURE_K, buf, bufsize);
487a1bf3f78SToomas Soome if (ret == -1) {
488a1bf3f78SToomas Soome free(buf);
489a1bf3f78SToomas Soome return (NULL);
490a1bf3f78SToomas Soome }
491a1bf3f78SToomas Soome return (buf);
492a1bf3f78SToomas Soome }
493a1bf3f78SToomas Soome
494a1bf3f78SToomas Soome /*
495a1bf3f78SToomas Soome * Shim for taking commands from BF and passing them out to 'standard'
496a1bf3f78SToomas Soome * argv/argc command functions.
497a1bf3f78SToomas Soome */
498a1bf3f78SToomas Soome static void
bf_command(ficlVm * vm)499a1bf3f78SToomas Soome bf_command(ficlVm *vm)
500a1bf3f78SToomas Soome {
501a1bf3f78SToomas Soome char *name, *line, *tail, *cp;
502a1bf3f78SToomas Soome size_t len;
503a1bf3f78SToomas Soome struct bootblk_command *cmdp;
504a1bf3f78SToomas Soome bootblk_cmd_t *cmd;
505a1bf3f78SToomas Soome int nstrings, i;
506a1bf3f78SToomas Soome int argc, result;
507a1bf3f78SToomas Soome char **argv;
508a1bf3f78SToomas Soome
509a1bf3f78SToomas Soome /* Get the name of the current word */
510a1bf3f78SToomas Soome name = vm->runningWord->name;
511a1bf3f78SToomas Soome
512a1bf3f78SToomas Soome /* Find our command structure */
513a1bf3f78SToomas Soome cmd = NULL;
514a1bf3f78SToomas Soome STAILQ_FOREACH(cmdp, &commands, next) {
515a1bf3f78SToomas Soome if ((cmdp->c_name != NULL) && strcmp(name, cmdp->c_name) == 0)
516a1bf3f78SToomas Soome cmd = cmdp->c_fn;
517a1bf3f78SToomas Soome }
518a1bf3f78SToomas Soome if (cmd == NULL)
519a1bf3f78SToomas Soome printf("callout for unknown command '%s'\n", name);
520a1bf3f78SToomas Soome
521a1bf3f78SToomas Soome /* Check whether we have been compiled or are being interpreted */
522a1bf3f78SToomas Soome if (ficlStackPopInteger(ficlVmGetDataStack(vm))) {
523a1bf3f78SToomas Soome /*
524a1bf3f78SToomas Soome * Get parameters from stack, in the format:
525a1bf3f78SToomas Soome * an un ... a2 u2 a1 u1 n --
526a1bf3f78SToomas Soome * Where n is the number of strings, a/u are pairs of
527a1bf3f78SToomas Soome * address/size for strings, and they will be concatenated
528a1bf3f78SToomas Soome * in LIFO order.
529a1bf3f78SToomas Soome */
530a1bf3f78SToomas Soome nstrings = ficlStackPopInteger(ficlVmGetDataStack(vm));
531a1bf3f78SToomas Soome for (i = 0, len = 0; i < nstrings; i++)
532a1bf3f78SToomas Soome len += ficlStackFetch(ficlVmGetDataStack(vm), i * 2).i + 1;
533a1bf3f78SToomas Soome line = malloc(strlen(name) + len + 1);
534a1bf3f78SToomas Soome strcpy(line, name);
535a1bf3f78SToomas Soome
536a1bf3f78SToomas Soome if (nstrings)
537a1bf3f78SToomas Soome for (i = 0; i < nstrings; i++) {
538a1bf3f78SToomas Soome len = ficlStackPopInteger(
539a1bf3f78SToomas Soome ficlVmGetDataStack(vm));
540a1bf3f78SToomas Soome cp = ficlStackPopPointer(
541a1bf3f78SToomas Soome ficlVmGetDataStack(vm));
542a1bf3f78SToomas Soome strcat(line, " ");
543a1bf3f78SToomas Soome strncat(line, cp, len);
544a1bf3f78SToomas Soome }
545a1bf3f78SToomas Soome } else {
546a1bf3f78SToomas Soome /* Get remainder of invocation */
547a1bf3f78SToomas Soome tail = ficlVmGetInBuf(vm);
548a1bf3f78SToomas Soome for (cp = tail, len = 0;
549a1bf3f78SToomas Soome cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++)
550a1bf3f78SToomas Soome ;
551a1bf3f78SToomas Soome
552a1bf3f78SToomas Soome line = malloc(strlen(name) + len + 2);
553a1bf3f78SToomas Soome strcpy(line, name);
554a1bf3f78SToomas Soome if (len > 0) {
555a1bf3f78SToomas Soome strcat(line, " ");
556a1bf3f78SToomas Soome strncat(line, tail, len);
557a1bf3f78SToomas Soome ficlVmUpdateTib(vm, tail + len);
558a1bf3f78SToomas Soome }
559a1bf3f78SToomas Soome }
560a1bf3f78SToomas Soome
561a1bf3f78SToomas Soome command_errmsg = command_errbuf;
562a1bf3f78SToomas Soome command_errbuf[0] = 0;
563a1bf3f78SToomas Soome if (!parse(&argc, &argv, line)) {
564a1bf3f78SToomas Soome result = (cmd)(argc, argv);
565a1bf3f78SToomas Soome free(argv);
566a1bf3f78SToomas Soome } else {
567a1bf3f78SToomas Soome result = BF_PARSE;
568a1bf3f78SToomas Soome }
569a1bf3f78SToomas Soome free(line);
570a1bf3f78SToomas Soome /*
571a1bf3f78SToomas Soome * If there was error during nested ficlExec(), we may no longer have
572a1bf3f78SToomas Soome * valid environment to return. Throw all exceptions from here.
573a1bf3f78SToomas Soome */
574a1bf3f78SToomas Soome if (result != 0)
575a1bf3f78SToomas Soome ficlVmThrow(vm, result);
576a1bf3f78SToomas Soome /* This is going to be thrown!!! */
577a1bf3f78SToomas Soome ficlStackPushInteger(ficlVmGetDataStack(vm), result);
578a1bf3f78SToomas Soome }
579a1bf3f78SToomas Soome
580a1bf3f78SToomas Soome static char *
get_currdev(void)581a1bf3f78SToomas Soome get_currdev(void)
582a1bf3f78SToomas Soome {
583a1bf3f78SToomas Soome int ret;
584a1bf3f78SToomas Soome char *currdev;
585a1bf3f78SToomas Soome FILE *fp;
586a1bf3f78SToomas Soome struct mnttab mpref = {0};
587a1bf3f78SToomas Soome struct mnttab mp = {0};
588a1bf3f78SToomas Soome
589a1bf3f78SToomas Soome mpref.mnt_mountp = "/";
590a1bf3f78SToomas Soome fp = fopen(MNTTAB, "r");
591a1bf3f78SToomas Soome
592a1bf3f78SToomas Soome /* do the best we can to return something... */
593a1bf3f78SToomas Soome if (fp == NULL)
594a1bf3f78SToomas Soome return (strdup(":"));
595a1bf3f78SToomas Soome
596a1bf3f78SToomas Soome ret = getmntany(fp, &mp, &mpref);
597a1bf3f78SToomas Soome (void) fclose(fp);
598a1bf3f78SToomas Soome if (ret == 0)
599a1bf3f78SToomas Soome (void) asprintf(&currdev, "zfs:%s:", mp.mnt_special);
600a1bf3f78SToomas Soome else
601a1bf3f78SToomas Soome return (strdup(":"));
602a1bf3f78SToomas Soome
603a1bf3f78SToomas Soome return (currdev);
604a1bf3f78SToomas Soome }
605a1bf3f78SToomas Soome
606a1bf3f78SToomas Soome /*
607a1bf3f78SToomas Soome * Replace a word definition (a builtin command) with another
608a1bf3f78SToomas Soome * one that:
609a1bf3f78SToomas Soome *
610a1bf3f78SToomas Soome * - Throw error results instead of returning them on the stack
611a1bf3f78SToomas Soome * - Pass a flag indicating whether the word was compiled or is
612a1bf3f78SToomas Soome * being interpreted.
613a1bf3f78SToomas Soome *
614a1bf3f78SToomas Soome * There is one major problem with builtins that cannot be overcome
615a1bf3f78SToomas Soome * in anyway, except by outlawing it. We want builtins to behave
616a1bf3f78SToomas Soome * differently depending on whether they have been compiled or they
617a1bf3f78SToomas Soome * are being interpreted. Notice that this is *not* the interpreter's
618a1bf3f78SToomas Soome * current state. For example:
619a1bf3f78SToomas Soome *
620a1bf3f78SToomas Soome * : example ls ; immediate
621a1bf3f78SToomas Soome * : problem example ; \ "ls" gets executed while compiling
622a1bf3f78SToomas Soome * example \ "ls" gets executed while interpreting
623a1bf3f78SToomas Soome *
624a1bf3f78SToomas Soome * Notice that, though the current state is different in the two
625a1bf3f78SToomas Soome * invocations of "example", in both cases "ls" has been
626a1bf3f78SToomas Soome * *compiled in*, which is what we really want.
627a1bf3f78SToomas Soome *
628a1bf3f78SToomas Soome * The problem arises when you tick the builtin. For example:
629a1bf3f78SToomas Soome *
630a1bf3f78SToomas Soome * : example-1 ['] ls postpone literal ; immediate
631a1bf3f78SToomas Soome * : example-2 example-1 execute ; immediate
632a1bf3f78SToomas Soome * : problem example-2 ;
633a1bf3f78SToomas Soome * example-2
634a1bf3f78SToomas Soome *
635a1bf3f78SToomas Soome * We have no way, when we get EXECUTEd, of knowing what our behavior
636a1bf3f78SToomas Soome * should be. Thus, our only alternative is to "outlaw" this. See RFI
637a1bf3f78SToomas Soome * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related
638a1bf3f78SToomas Soome * problem, concerning compile semantics.
639a1bf3f78SToomas Soome *
640a1bf3f78SToomas Soome * The problem is compounded by the fact that "' builtin CATCH" is valid
641a1bf3f78SToomas Soome * and desirable. The only solution is to create an intermediary word.
642a1bf3f78SToomas Soome * For example:
643a1bf3f78SToomas Soome *
644a1bf3f78SToomas Soome * : my-ls ls ;
645a1bf3f78SToomas Soome * : example ['] my-ls catch ;
646a1bf3f78SToomas Soome *
647a1bf3f78SToomas Soome * So, with the below implementation, here is a summary of the behavior
648a1bf3f78SToomas Soome * of builtins:
649a1bf3f78SToomas Soome *
650a1bf3f78SToomas Soome * ls -l \ "interpret" behavior, ie,
651a1bf3f78SToomas Soome * \ takes parameters from TIB
652a1bf3f78SToomas Soome * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie,
653a1bf3f78SToomas Soome * \ takes parameters from the stack
654a1bf3f78SToomas Soome * : ex-2 ['] ls catch ; immediate \ undefined behavior
655a1bf3f78SToomas Soome * : ex-3 ['] ls catch ; \ undefined behavior
656a1bf3f78SToomas Soome * ex-2 ex-3 \ "interpret" behavior,
657a1bf3f78SToomas Soome * \ catch works
658a1bf3f78SToomas Soome * : ex-4 ex-2 ; \ "compile" behavior,
659a1bf3f78SToomas Soome * \ catch does not work
660a1bf3f78SToomas Soome * : ex-5 ex-3 ; immediate \ same as ex-2
661a1bf3f78SToomas Soome * : ex-6 ex-3 ; \ same as ex-3
662a1bf3f78SToomas Soome * : ex-7 ['] ex-1 catch ; \ "compile" behavior,
663a1bf3f78SToomas Soome * \ catch works
664a1bf3f78SToomas Soome * : ex-8 postpone ls ; immediate \ same as ex-2
665a1bf3f78SToomas Soome * : ex-9 postpone ls ; \ same as ex-3
666a1bf3f78SToomas Soome *
667a1bf3f78SToomas Soome * As the definition below is particularly tricky, and it's side effects
668a1bf3f78SToomas Soome * must be well understood by those playing with it, I'll be heavy on
669a1bf3f78SToomas Soome * the comments.
670a1bf3f78SToomas Soome *
671a1bf3f78SToomas Soome * (if you edit this definition, pay attention to trailing spaces after
672a1bf3f78SToomas Soome * each word -- I warned you! :-) )
673a1bf3f78SToomas Soome */
674a1bf3f78SToomas Soome #define BUILTIN_CONSTRUCTOR \
675a1bf3f78SToomas Soome ": builtin: " \
676a1bf3f78SToomas Soome ">in @ " /* save the tib index pointer */ \
677a1bf3f78SToomas Soome "' " /* get next word's xt */ \
678a1bf3f78SToomas Soome "swap >in ! " /* point again to next word */ \
679a1bf3f78SToomas Soome "create " /* create a new definition of the next word */ \
680a1bf3f78SToomas Soome ", " /* save previous definition's xt */ \
681a1bf3f78SToomas Soome "immediate " /* make the new definition an immediate word */ \
682a1bf3f78SToomas Soome \
683a1bf3f78SToomas Soome "does> " /* Now, the *new* definition will: */ \
684a1bf3f78SToomas Soome "state @ if " /* if in compiling state: */ \
685a1bf3f78SToomas Soome "1 postpone literal " /* pass 1 flag to indicate compile */ \
686a1bf3f78SToomas Soome "@ compile, " /* compile in previous definition */ \
687a1bf3f78SToomas Soome "postpone throw " /* throw stack-returned result */ \
688a1bf3f78SToomas Soome "else " /* if in interpreting state: */ \
689a1bf3f78SToomas Soome "0 swap " /* pass 0 flag to indicate interpret */ \
690a1bf3f78SToomas Soome "@ execute " /* call previous definition */ \
691a1bf3f78SToomas Soome "throw " /* throw stack-returned result */ \
692a1bf3f78SToomas Soome "then ; "
693a1bf3f78SToomas Soome
694a1bf3f78SToomas Soome extern int ficlExecFD(ficlVm *, int);
695a1bf3f78SToomas Soome #define COMMAND_SET(ptr, name, desc, fn) \
696a1bf3f78SToomas Soome ptr = malloc(sizeof (struct bootblk_command)); \
697a1bf3f78SToomas Soome ptr->c_name = (name); \
698a1bf3f78SToomas Soome ptr->c_desc = (desc); \
699a1bf3f78SToomas Soome ptr->c_fn = (fn);
700a1bf3f78SToomas Soome
701a1bf3f78SToomas Soome /*
702a1bf3f78SToomas Soome * Initialise the Forth interpreter, create all our commands as words.
703a1bf3f78SToomas Soome */
704a1bf3f78SToomas Soome ficlVm *
bf_init(const char * rc,ficlOutputFunction out)705a1bf3f78SToomas Soome bf_init(const char *rc, ficlOutputFunction out)
706a1bf3f78SToomas Soome {
707a1bf3f78SToomas Soome struct bootblk_command *cmdp;
708a1bf3f78SToomas Soome char create_buf[41]; /* 31 characters-long builtins */
709a1bf3f78SToomas Soome char *buf;
710a1bf3f78SToomas Soome int fd, rv;
711a1bf3f78SToomas Soome ficlSystemInformation *fsi;
712a1bf3f78SToomas Soome ficlDictionary *dict;
713a1bf3f78SToomas Soome ficlDictionary *env;
714a1bf3f78SToomas Soome
715a1bf3f78SToomas Soome /* set up commands list */
716a1bf3f78SToomas Soome STAILQ_INIT(&commands);
717a1bf3f78SToomas Soome COMMAND_SET(cmdp, "help", "detailed help", command_help);
718a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
719a1bf3f78SToomas Soome COMMAND_SET(cmdp, "?", "list commands", command_commandlist);
720a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
721a1bf3f78SToomas Soome COMMAND_SET(cmdp, "show", "show variable(s)", command_show);
722a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
723a1bf3f78SToomas Soome COMMAND_SET(cmdp, "printenv", "show variable(s)", command_show);
724a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
725a1bf3f78SToomas Soome COMMAND_SET(cmdp, "set", "set a variable", command_set);
726a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
727a1bf3f78SToomas Soome COMMAND_SET(cmdp, "setprop", "set a variable", command_setprop);
728a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
729a1bf3f78SToomas Soome COMMAND_SET(cmdp, "unset", "unset a variable", command_unset);
730a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
731a1bf3f78SToomas Soome COMMAND_SET(cmdp, "echo", "echo arguments", command_echo);
732a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
733a1bf3f78SToomas Soome COMMAND_SET(cmdp, "read", "read input from the terminal", command_read);
734a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
735a1bf3f78SToomas Soome COMMAND_SET(cmdp, "more", "show contents of a file", command_more);
736a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
737a1bf3f78SToomas Soome COMMAND_SET(cmdp, "ls", "list files", command_ls);
738a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
739a1bf3f78SToomas Soome COMMAND_SET(cmdp, "include", "read commands from a file",
740a1bf3f78SToomas Soome command_include);
741a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
742a1bf3f78SToomas Soome COMMAND_SET(cmdp, "boot", "boot a file or loaded kernel", command_boot);
743a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
744a1bf3f78SToomas Soome COMMAND_SET(cmdp, "autoboot", "boot automatically after a delay",
745a1bf3f78SToomas Soome command_autoboot);
746a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
747a1bf3f78SToomas Soome COMMAND_SET(cmdp, "load", "load a kernel or module", command_load);
748a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
749a1bf3f78SToomas Soome COMMAND_SET(cmdp, "unload", "unload all modules", command_unload);
750a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
751a1bf3f78SToomas Soome COMMAND_SET(cmdp, "reboot", "reboot the system", command_reboot);
752a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&commands, cmdp, next);
753a1bf3f78SToomas Soome
754a1bf3f78SToomas Soome fsi = malloc(sizeof (ficlSystemInformation));
755a1bf3f78SToomas Soome ficlSystemInformationInitialize(fsi);
756a1bf3f78SToomas Soome fsi->textOut = out;
757a1bf3f78SToomas Soome fsi->dictionarySize = BF_DICTSIZE;
758a1bf3f78SToomas Soome
759a1bf3f78SToomas Soome bf_sys = ficlSystemCreate(fsi);
760a1bf3f78SToomas Soome free(fsi);
761a1bf3f78SToomas Soome ficlSystemCompileExtras(bf_sys);
762a1bf3f78SToomas Soome bf_vm = ficlSystemCreateVm(bf_sys);
763a1bf3f78SToomas Soome
764a1bf3f78SToomas Soome buf = isadir();
765a1bf3f78SToomas Soome if (buf == NULL || strcmp(buf, "amd64") != 0) {
766a1bf3f78SToomas Soome (void) setenv("ISADIR", "", 1);
767a1bf3f78SToomas Soome } else {
768a1bf3f78SToomas Soome (void) setenv("ISADIR", buf, 1);
769a1bf3f78SToomas Soome }
770a1bf3f78SToomas Soome if (buf != NULL)
771a1bf3f78SToomas Soome free(buf);
772a1bf3f78SToomas Soome buf = get_currdev();
773a1bf3f78SToomas Soome (void) setenv("currdev", buf, 1);
774a1bf3f78SToomas Soome free(buf);
775a1bf3f78SToomas Soome
776a1bf3f78SToomas Soome /* Put all private definitions in a "builtins" vocabulary */
777a1bf3f78SToomas Soome rv = ficlVmEvaluate(bf_vm,
778a1bf3f78SToomas Soome "vocabulary builtins also builtins definitions");
779a1bf3f78SToomas Soome if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
780a1bf3f78SToomas Soome printf("error interpreting forth: %d\n", rv);
781a1bf3f78SToomas Soome exit(1);
782a1bf3f78SToomas Soome }
783a1bf3f78SToomas Soome
784a1bf3f78SToomas Soome /* Builtin constructor word */
785a1bf3f78SToomas Soome rv = ficlVmEvaluate(bf_vm, BUILTIN_CONSTRUCTOR);
786a1bf3f78SToomas Soome if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
787a1bf3f78SToomas Soome printf("error interpreting forth: %d\n", rv);
788a1bf3f78SToomas Soome exit(1);
789a1bf3f78SToomas Soome }
790a1bf3f78SToomas Soome
791a1bf3f78SToomas Soome /* make all commands appear as Forth words */
792a1bf3f78SToomas Soome dict = ficlSystemGetDictionary(bf_sys);
793a1bf3f78SToomas Soome cmdp = NULL;
794a1bf3f78SToomas Soome STAILQ_FOREACH(cmdp, &commands, next) {
795a1bf3f78SToomas Soome ficlDictionaryAppendPrimitive(dict, (char *)cmdp->c_name,
796a1bf3f78SToomas Soome bf_command, FICL_WORD_DEFAULT);
797a1bf3f78SToomas Soome rv = ficlVmEvaluate(bf_vm, "forth definitions builtins");
798a1bf3f78SToomas Soome if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
799a1bf3f78SToomas Soome printf("error interpreting forth: %d\n", rv);
800a1bf3f78SToomas Soome exit(1);
801a1bf3f78SToomas Soome }
802a1bf3f78SToomas Soome sprintf(create_buf, "builtin: %s", cmdp->c_name);
803a1bf3f78SToomas Soome rv = ficlVmEvaluate(bf_vm, create_buf);
804a1bf3f78SToomas Soome if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
805a1bf3f78SToomas Soome printf("error interpreting forth: %d\n", rv);
806a1bf3f78SToomas Soome exit(1);
807a1bf3f78SToomas Soome }
808a1bf3f78SToomas Soome rv = ficlVmEvaluate(bf_vm, "builtins definitions");
809a1bf3f78SToomas Soome if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
810a1bf3f78SToomas Soome printf("error interpreting forth: %d\n", rv);
811a1bf3f78SToomas Soome exit(1);
812a1bf3f78SToomas Soome }
813a1bf3f78SToomas Soome }
814a1bf3f78SToomas Soome rv = ficlVmEvaluate(bf_vm, "only forth definitions");
815a1bf3f78SToomas Soome if (rv != FICL_VM_STATUS_OUT_OF_TEXT) {
816a1bf3f78SToomas Soome printf("error interpreting forth: %d\n", rv);
817a1bf3f78SToomas Soome exit(1);
818a1bf3f78SToomas Soome }
819a1bf3f78SToomas Soome
820a1bf3f78SToomas Soome /*
821a1bf3f78SToomas Soome * Export some version numbers so that code can detect the
822a1bf3f78SToomas Soome * loader/host version
823a1bf3f78SToomas Soome */
824a1bf3f78SToomas Soome env = ficlSystemGetEnvironment(bf_sys);
825a1bf3f78SToomas Soome ficlDictionarySetConstant(env, "loader_version",
826a1bf3f78SToomas Soome (bootprog_rev[0] - '0') * 10 + (bootprog_rev[2] - '0'));
827a1bf3f78SToomas Soome
828a1bf3f78SToomas Soome /* try to load and run init file if present */
829a1bf3f78SToomas Soome if (rc == NULL)
830a1bf3f78SToomas Soome rc = "/boot/forth/boot.4th";
831a1bf3f78SToomas Soome if (*rc != '\0') {
832a1bf3f78SToomas Soome fd = open(rc, O_RDONLY);
833a1bf3f78SToomas Soome if (fd != -1) {
834a1bf3f78SToomas Soome (void) ficlExecFD(bf_vm, fd);
835a1bf3f78SToomas Soome close(fd);
836a1bf3f78SToomas Soome }
837a1bf3f78SToomas Soome }
838a1bf3f78SToomas Soome
839a1bf3f78SToomas Soome return (bf_vm);
840a1bf3f78SToomas Soome }
841a1bf3f78SToomas Soome
842a1bf3f78SToomas Soome void
bf_fini(void)843a1bf3f78SToomas Soome bf_fini(void)
844a1bf3f78SToomas Soome {
845a1bf3f78SToomas Soome ficlSystemDestroy(bf_sys);
846a1bf3f78SToomas Soome }
847a1bf3f78SToomas Soome
848a1bf3f78SToomas Soome /*
849a1bf3f78SToomas Soome * Feed a line of user input to the Forth interpreter
850a1bf3f78SToomas Soome */
851a1bf3f78SToomas Soome int
bf_run(char * line)852a1bf3f78SToomas Soome bf_run(char *line)
853a1bf3f78SToomas Soome {
854a1bf3f78SToomas Soome int result;
855a1bf3f78SToomas Soome ficlString s;
856a1bf3f78SToomas Soome
857a1bf3f78SToomas Soome FICL_STRING_SET_FROM_CSTRING(s, line);
858a1bf3f78SToomas Soome result = ficlVmExecuteString(bf_vm, s);
859a1bf3f78SToomas Soome
860a1bf3f78SToomas Soome switch (result) {
861a1bf3f78SToomas Soome case FICL_VM_STATUS_OUT_OF_TEXT:
862a1bf3f78SToomas Soome case FICL_VM_STATUS_ABORTQ:
863a1bf3f78SToomas Soome case FICL_VM_STATUS_QUIT:
864a1bf3f78SToomas Soome case FICL_VM_STATUS_ERROR_EXIT:
865a1bf3f78SToomas Soome break;
866a1bf3f78SToomas Soome case FICL_VM_STATUS_USER_EXIT:
867a1bf3f78SToomas Soome break;
868a1bf3f78SToomas Soome case FICL_VM_STATUS_ABORT:
869a1bf3f78SToomas Soome printf("Aborted!\n");
870a1bf3f78SToomas Soome break;
871a1bf3f78SToomas Soome case BF_PARSE:
872a1bf3f78SToomas Soome printf("Parse error!\n");
873a1bf3f78SToomas Soome break;
874a1bf3f78SToomas Soome default:
875af7edebeSToomas Soome if (command_errmsg != NULL) {
876a1bf3f78SToomas Soome printf("%s\n", command_errmsg);
877af7edebeSToomas Soome command_errmsg = NULL;
878af7edebeSToomas Soome }
879a1bf3f78SToomas Soome }
880a1bf3f78SToomas Soome
881a1bf3f78SToomas Soome setenv("interpret", bf_vm->state ? "" : "ok", 1);
882a1bf3f78SToomas Soome
883a1bf3f78SToomas Soome return (result);
884a1bf3f78SToomas Soome }
885a1bf3f78SToomas Soome
886a1bf3f78SToomas Soome char *
get_dev(const char * path)887a1bf3f78SToomas Soome get_dev(const char *path)
888a1bf3f78SToomas Soome {
889a1bf3f78SToomas Soome FILE *fp;
890a1bf3f78SToomas Soome struct mnttab mpref = {0};
891a1bf3f78SToomas Soome struct mnttab mp = {0};
892a1bf3f78SToomas Soome char *currdev;
893a1bf3f78SToomas Soome int ret;
894a1bf3f78SToomas Soome char *buf;
895a1bf3f78SToomas Soome char *tmppath;
896a1bf3f78SToomas Soome char *tmpdev;
897a1bf3f78SToomas Soome char *cwd = NULL;
898a1bf3f78SToomas Soome
899a1bf3f78SToomas Soome fp = fopen(MNTTAB, "r");
900a1bf3f78SToomas Soome
901a1bf3f78SToomas Soome /* do the best we can to return something... */
902a1bf3f78SToomas Soome if (fp == NULL)
903a1bf3f78SToomas Soome return (strdup(path));
904a1bf3f78SToomas Soome
905a1bf3f78SToomas Soome /*
906a1bf3f78SToomas Soome * the path can have device provided, check for it
907a1bf3f78SToomas Soome * and extract it.
908a1bf3f78SToomas Soome */
909a1bf3f78SToomas Soome buf = strrchr(path, ':');
910a1bf3f78SToomas Soome if (buf != NULL) {
911a1bf3f78SToomas Soome tmppath = buf+1; /* real path */
912a1bf3f78SToomas Soome buf = strchr(path, ':'); /* skip zfs: */
913a1bf3f78SToomas Soome buf++;
914a1bf3f78SToomas Soome tmpdev = strdup(buf);
915a1bf3f78SToomas Soome buf = strchr(tmpdev, ':'); /* get ending : */
916a1bf3f78SToomas Soome *buf = '\0';
917a1bf3f78SToomas Soome } else {
918a1bf3f78SToomas Soome tmppath = (char *)path;
919a1bf3f78SToomas Soome if (tmppath[0] != '/')
920a1bf3f78SToomas Soome if ((cwd = getcwd(NULL, PATH_MAX)) == NULL) {
921a1bf3f78SToomas Soome (void) fclose(fp);
922a1bf3f78SToomas Soome return (strdup(path));
923a1bf3f78SToomas Soome }
924a1bf3f78SToomas Soome
925a1bf3f78SToomas Soome currdev = getenv("currdev");
926a1bf3f78SToomas Soome buf = strchr(currdev, ':'); /* skip zfs: */
927a1bf3f78SToomas Soome if (buf == NULL) {
928a1bf3f78SToomas Soome (void) fclose(fp);
929a1bf3f78SToomas Soome return (strdup(path));
930a1bf3f78SToomas Soome }
931a1bf3f78SToomas Soome buf++;
932a1bf3f78SToomas Soome tmpdev = strdup(buf);
933a1bf3f78SToomas Soome buf = strchr(tmpdev, ':'); /* get ending : */
934a1bf3f78SToomas Soome *buf = '\0';
935a1bf3f78SToomas Soome }
936a1bf3f78SToomas Soome
937a1bf3f78SToomas Soome mpref.mnt_special = tmpdev;
938a1bf3f78SToomas Soome ret = getmntany(fp, &mp, &mpref);
939a1bf3f78SToomas Soome (void) fclose(fp);
940a1bf3f78SToomas Soome free(tmpdev);
941a1bf3f78SToomas Soome
942a1bf3f78SToomas Soome if (cwd == NULL)
943a1bf3f78SToomas Soome (void) asprintf(&buf, "%s/%s", ret? "":mp.mnt_mountp, tmppath);
944a1bf3f78SToomas Soome else {
945a1bf3f78SToomas Soome (void) asprintf(&buf, "%s/%s/%s", ret? "":mp.mnt_mountp, cwd,
946a1bf3f78SToomas Soome tmppath);
947a1bf3f78SToomas Soome free(cwd);
948a1bf3f78SToomas Soome }
949a1bf3f78SToomas Soome return (buf);
950a1bf3f78SToomas Soome }
951a1bf3f78SToomas Soome
952a1bf3f78SToomas Soome static void
ngets(char * buf,int n)953a1bf3f78SToomas Soome ngets(char *buf, int n)
954a1bf3f78SToomas Soome {
955a1bf3f78SToomas Soome int c;
956a1bf3f78SToomas Soome char *lp;
957a1bf3f78SToomas Soome
958a1bf3f78SToomas Soome for (lp = buf; ; )
959a1bf3f78SToomas Soome switch (c = getchar() & 0177) {
960a1bf3f78SToomas Soome case '\n':
961a1bf3f78SToomas Soome case '\r':
962a1bf3f78SToomas Soome *lp = '\0';
963a1bf3f78SToomas Soome putchar('\n');
964a1bf3f78SToomas Soome return;
965a1bf3f78SToomas Soome case '\b':
966a1bf3f78SToomas Soome case '\177':
967a1bf3f78SToomas Soome if (lp > buf) {
968a1bf3f78SToomas Soome lp--;
969a1bf3f78SToomas Soome putchar('\b');
970a1bf3f78SToomas Soome putchar(' ');
971a1bf3f78SToomas Soome putchar('\b');
972a1bf3f78SToomas Soome }
973a1bf3f78SToomas Soome break;
974a1bf3f78SToomas Soome case 'r'&037: {
975a1bf3f78SToomas Soome char *p;
976a1bf3f78SToomas Soome
977a1bf3f78SToomas Soome putchar('\n');
978a1bf3f78SToomas Soome for (p = buf; p < lp; ++p)
979a1bf3f78SToomas Soome putchar(*p);
980a1bf3f78SToomas Soome break;
981a1bf3f78SToomas Soome }
982a1bf3f78SToomas Soome case 'u'&037:
983a1bf3f78SToomas Soome case 'w'&037:
984a1bf3f78SToomas Soome lp = buf;
985a1bf3f78SToomas Soome putchar('\n');
986a1bf3f78SToomas Soome break;
987a1bf3f78SToomas Soome default:
988a1bf3f78SToomas Soome if ((n < 1) || ((lp - buf) < n - 1)) {
989a1bf3f78SToomas Soome *lp++ = c;
990a1bf3f78SToomas Soome putchar(c);
991a1bf3f78SToomas Soome }
992a1bf3f78SToomas Soome }
993a1bf3f78SToomas Soome /*NOTREACHED*/
994a1bf3f78SToomas Soome }
995a1bf3f78SToomas Soome
996a1bf3f78SToomas Soome static int
fgetstr(char * buf,int size,int fd)997a1bf3f78SToomas Soome fgetstr(char *buf, int size, int fd)
998a1bf3f78SToomas Soome {
999a1bf3f78SToomas Soome char c;
1000a1bf3f78SToomas Soome int err, len;
1001a1bf3f78SToomas Soome
1002a1bf3f78SToomas Soome size--; /* leave space for terminator */
1003a1bf3f78SToomas Soome len = 0;
1004a1bf3f78SToomas Soome while (size != 0) {
1005a1bf3f78SToomas Soome err = read(fd, &c, sizeof (c));
1006a1bf3f78SToomas Soome if (err < 0) /* read error */
1007a1bf3f78SToomas Soome return (-1);
1008a1bf3f78SToomas Soome
1009a1bf3f78SToomas Soome if (err == 0) { /* EOF */
1010a1bf3f78SToomas Soome if (len == 0)
1011a1bf3f78SToomas Soome return (-1); /* nothing to read */
1012a1bf3f78SToomas Soome break;
1013a1bf3f78SToomas Soome }
1014a1bf3f78SToomas Soome if ((c == '\r') || (c == '\n')) /* line terminators */
1015a1bf3f78SToomas Soome break;
1016a1bf3f78SToomas Soome *buf++ = c; /* keep char */
1017a1bf3f78SToomas Soome size--;
1018a1bf3f78SToomas Soome len++;
1019a1bf3f78SToomas Soome }
1020a1bf3f78SToomas Soome *buf = 0;
1021a1bf3f78SToomas Soome return (len);
1022a1bf3f78SToomas Soome }
1023a1bf3f78SToomas Soome
1024a1bf3f78SToomas Soome static char *
unargv(int argc,char * argv[])1025a1bf3f78SToomas Soome unargv(int argc, char *argv[])
1026a1bf3f78SToomas Soome {
1027a1bf3f78SToomas Soome size_t hlong;
1028a1bf3f78SToomas Soome int i;
1029a1bf3f78SToomas Soome char *cp;
1030a1bf3f78SToomas Soome
1031a1bf3f78SToomas Soome for (i = 0, hlong = 0; i < argc; i++)
1032a1bf3f78SToomas Soome hlong += strlen(argv[i]) + 2;
1033a1bf3f78SToomas Soome
1034a1bf3f78SToomas Soome if (hlong == 0)
1035a1bf3f78SToomas Soome return (NULL);
1036a1bf3f78SToomas Soome
1037a1bf3f78SToomas Soome cp = malloc(hlong);
1038a1bf3f78SToomas Soome cp[0] = 0;
1039a1bf3f78SToomas Soome for (i = 0; i < argc; i++) {
1040a1bf3f78SToomas Soome strcat(cp, argv[i]);
1041a1bf3f78SToomas Soome if (i < (argc - 1))
1042a1bf3f78SToomas Soome strcat(cp, " ");
1043a1bf3f78SToomas Soome }
1044a1bf3f78SToomas Soome
1045a1bf3f78SToomas Soome return (cp);
1046a1bf3f78SToomas Soome }
1047a1bf3f78SToomas Soome
1048a1bf3f78SToomas Soome /*
1049a1bf3f78SToomas Soome * Help is read from a formatted text file.
1050a1bf3f78SToomas Soome *
1051a1bf3f78SToomas Soome * Entries in the file are formatted as:
1052a1bf3f78SToomas Soome * # Ttopic [Ssubtopic] Ddescription
1053a1bf3f78SToomas Soome * help
1054a1bf3f78SToomas Soome * text
1055a1bf3f78SToomas Soome * here
1056a1bf3f78SToomas Soome * #
1057a1bf3f78SToomas Soome *
1058a1bf3f78SToomas Soome * Note that for code simplicity's sake, the above format must be followed
1059a1bf3f78SToomas Soome * exactly.
1060a1bf3f78SToomas Soome *
1061a1bf3f78SToomas Soome * Subtopic entries must immediately follow the topic (this is used to
1062a1bf3f78SToomas Soome * produce the listing of subtopics).
1063a1bf3f78SToomas Soome *
1064a1bf3f78SToomas Soome * If no argument(s) are supplied by the user, the help for 'help' is displayed.
1065a1bf3f78SToomas Soome */
1066a1bf3f78SToomas Soome static int
help_getnext(int fd,char ** topic,char ** subtopic,char ** desc)1067a1bf3f78SToomas Soome help_getnext(int fd, char **topic, char **subtopic, char **desc)
1068a1bf3f78SToomas Soome {
1069a1bf3f78SToomas Soome char line[81], *cp, *ep;
1070a1bf3f78SToomas Soome
1071a1bf3f78SToomas Soome for (;;) {
1072a1bf3f78SToomas Soome if (fgetstr(line, 80, fd) < 0)
1073a1bf3f78SToomas Soome return (0);
1074a1bf3f78SToomas Soome
1075a1bf3f78SToomas Soome if ((strlen(line) < 3) || (line[0] != '#') || (line[1] != ' '))
1076a1bf3f78SToomas Soome continue;
1077a1bf3f78SToomas Soome
1078a1bf3f78SToomas Soome *topic = *subtopic = *desc = NULL;
1079a1bf3f78SToomas Soome cp = line + 2;
1080a1bf3f78SToomas Soome while ((cp != NULL) && (*cp != 0)) {
1081a1bf3f78SToomas Soome ep = strchr(cp, ' ');
1082a1bf3f78SToomas Soome if ((*cp == 'T') && (*topic == NULL)) {
1083a1bf3f78SToomas Soome if (ep != NULL)
1084a1bf3f78SToomas Soome *ep++ = 0;
1085a1bf3f78SToomas Soome *topic = strdup(cp + 1);
1086a1bf3f78SToomas Soome } else if ((*cp == 'S') && (*subtopic == NULL)) {
1087a1bf3f78SToomas Soome if (ep != NULL)
1088a1bf3f78SToomas Soome *ep++ = 0;
1089a1bf3f78SToomas Soome *subtopic = strdup(cp + 1);
1090a1bf3f78SToomas Soome } else if (*cp == 'D') {
1091a1bf3f78SToomas Soome *desc = strdup(cp + 1);
1092a1bf3f78SToomas Soome ep = NULL;
1093a1bf3f78SToomas Soome }
1094a1bf3f78SToomas Soome cp = ep;
1095a1bf3f78SToomas Soome }
1096a1bf3f78SToomas Soome if (*topic == NULL) {
1097a1bf3f78SToomas Soome if (*subtopic != NULL)
1098a1bf3f78SToomas Soome free(*subtopic);
1099a1bf3f78SToomas Soome if (*desc != NULL)
1100a1bf3f78SToomas Soome free(*desc);
1101a1bf3f78SToomas Soome continue;
1102a1bf3f78SToomas Soome }
1103a1bf3f78SToomas Soome return (1);
1104a1bf3f78SToomas Soome }
1105a1bf3f78SToomas Soome }
1106a1bf3f78SToomas Soome
1107a1bf3f78SToomas Soome static int
help_emitsummary(char * topic,char * subtopic,char * desc)1108a1bf3f78SToomas Soome help_emitsummary(char *topic, char *subtopic, char *desc)
1109a1bf3f78SToomas Soome {
1110a1bf3f78SToomas Soome int i;
1111a1bf3f78SToomas Soome
1112a1bf3f78SToomas Soome pager_output(" ");
1113a1bf3f78SToomas Soome pager_output(topic);
1114a1bf3f78SToomas Soome i = strlen(topic);
1115a1bf3f78SToomas Soome if (subtopic != NULL) {
1116a1bf3f78SToomas Soome pager_output(" ");
1117a1bf3f78SToomas Soome pager_output(subtopic);
1118a1bf3f78SToomas Soome i += strlen(subtopic) + 1;
1119a1bf3f78SToomas Soome }
1120a1bf3f78SToomas Soome if (desc != NULL) {
1121a1bf3f78SToomas Soome do {
1122a1bf3f78SToomas Soome pager_output(" ");
1123a1bf3f78SToomas Soome } while (i++ < 30);
1124a1bf3f78SToomas Soome pager_output(desc);
1125a1bf3f78SToomas Soome }
1126a1bf3f78SToomas Soome return (pager_output("\n"));
1127a1bf3f78SToomas Soome }
1128a1bf3f78SToomas Soome
1129a1bf3f78SToomas Soome static int
command_help(int argc,char * argv[])1130a1bf3f78SToomas Soome command_help(int argc, char *argv[])
1131a1bf3f78SToomas Soome {
1132a1bf3f78SToomas Soome char buf[81]; /* XXX buffer size? */
1133a1bf3f78SToomas Soome int hfd, matched, doindex;
1134a1bf3f78SToomas Soome char *topic, *subtopic, *t, *s, *d;
1135a1bf3f78SToomas Soome
1136a1bf3f78SToomas Soome /* page the help text from our load path */
1137a1bf3f78SToomas Soome sprintf(buf, "/boot/loader.help");
1138a1bf3f78SToomas Soome if ((hfd = open(buf, O_RDONLY)) < 0) {
1139a1bf3f78SToomas Soome printf("Verbose help not available, "
1140a1bf3f78SToomas Soome "use '?' to list commands\n");
1141a1bf3f78SToomas Soome return (CMD_OK);
1142a1bf3f78SToomas Soome }
1143a1bf3f78SToomas Soome
1144a1bf3f78SToomas Soome /* pick up request from arguments */
1145a1bf3f78SToomas Soome topic = subtopic = NULL;
1146a1bf3f78SToomas Soome switch (argc) {
1147a1bf3f78SToomas Soome case 3:
1148a1bf3f78SToomas Soome subtopic = strdup(argv[2]);
1149*3451cb4fSToomas Soome /* FALLTHROUGH */
1150a1bf3f78SToomas Soome case 2:
1151a1bf3f78SToomas Soome topic = strdup(argv[1]);
1152a1bf3f78SToomas Soome break;
1153a1bf3f78SToomas Soome case 1:
1154a1bf3f78SToomas Soome topic = strdup("help");
1155a1bf3f78SToomas Soome break;
1156a1bf3f78SToomas Soome default:
1157a1bf3f78SToomas Soome command_errmsg = "usage is 'help <topic> [<subtopic>]";
1158a1bf3f78SToomas Soome close(hfd);
1159a1bf3f78SToomas Soome return (CMD_ERROR);
1160a1bf3f78SToomas Soome }
1161a1bf3f78SToomas Soome
1162a1bf3f78SToomas Soome /* magic "index" keyword */
1163a1bf3f78SToomas Soome doindex = strcmp(topic, "index") == 0;
1164a1bf3f78SToomas Soome matched = doindex;
1165a1bf3f78SToomas Soome
1166a1bf3f78SToomas Soome /* Scan the helpfile looking for help matching the request */
1167a1bf3f78SToomas Soome pager_open();
1168a1bf3f78SToomas Soome while (help_getnext(hfd, &t, &s, &d)) {
1169a1bf3f78SToomas Soome if (doindex) { /* dink around formatting */
1170a1bf3f78SToomas Soome if (help_emitsummary(t, s, d))
1171a1bf3f78SToomas Soome break;
1172a1bf3f78SToomas Soome
1173a1bf3f78SToomas Soome } else if (strcmp(topic, t)) {
1174a1bf3f78SToomas Soome /* topic mismatch */
1175a1bf3f78SToomas Soome /* nothing more on this topic, stop scanning */
1176a1bf3f78SToomas Soome if (matched)
1177a1bf3f78SToomas Soome break;
1178a1bf3f78SToomas Soome } else {
1179a1bf3f78SToomas Soome /* topic matched */
1180a1bf3f78SToomas Soome matched = 1;
1181a1bf3f78SToomas Soome if (((subtopic == NULL) && (s == NULL)) ||
1182a1bf3f78SToomas Soome ((subtopic != NULL) && (s != NULL) &&
1183a1bf3f78SToomas Soome strcmp(subtopic, s) == 0)) {
1184a1bf3f78SToomas Soome /* exact match, print text */
1185a1bf3f78SToomas Soome while ((fgetstr(buf, 80, hfd) >= 0) &&
1186a1bf3f78SToomas Soome (buf[0] != '#')) {
1187a1bf3f78SToomas Soome if (pager_output(buf))
1188a1bf3f78SToomas Soome break;
1189a1bf3f78SToomas Soome if (pager_output("\n"))
1190a1bf3f78SToomas Soome break;
1191a1bf3f78SToomas Soome }
1192a1bf3f78SToomas Soome } else if ((subtopic == NULL) && (s != NULL)) {
1193a1bf3f78SToomas Soome /* topic match, list subtopics */
1194a1bf3f78SToomas Soome if (help_emitsummary(t, s, d))
1195a1bf3f78SToomas Soome break;
1196a1bf3f78SToomas Soome }
1197a1bf3f78SToomas Soome }
1198a1bf3f78SToomas Soome free(t);
1199a1bf3f78SToomas Soome free(s);
1200a1bf3f78SToomas Soome free(d);
1201a1bf3f78SToomas Soome }
1202a1bf3f78SToomas Soome pager_close();
1203a1bf3f78SToomas Soome close(hfd);
1204a1bf3f78SToomas Soome if (!matched) {
1205a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1206a1bf3f78SToomas Soome "no help available for '%s'", topic);
1207a1bf3f78SToomas Soome free(topic);
1208a1bf3f78SToomas Soome if (subtopic)
1209a1bf3f78SToomas Soome free(subtopic);
1210a1bf3f78SToomas Soome return (CMD_ERROR);
1211a1bf3f78SToomas Soome }
1212a1bf3f78SToomas Soome free(topic);
1213a1bf3f78SToomas Soome if (subtopic)
1214a1bf3f78SToomas Soome free(subtopic);
1215a1bf3f78SToomas Soome return (CMD_OK);
1216a1bf3f78SToomas Soome }
1217a1bf3f78SToomas Soome
1218a1bf3f78SToomas Soome static int
command_commandlist(int argc,char * argv[])1219a1bf3f78SToomas Soome command_commandlist(int argc, char *argv[])
1220a1bf3f78SToomas Soome {
1221a1bf3f78SToomas Soome struct bootblk_command *cmdp;
1222a1bf3f78SToomas Soome int res;
1223a1bf3f78SToomas Soome char name[20];
1224a1bf3f78SToomas Soome
1225a1bf3f78SToomas Soome res = 0;
1226a1bf3f78SToomas Soome pager_open();
1227a1bf3f78SToomas Soome res = pager_output("Available commands:\n");
1228a1bf3f78SToomas Soome cmdp = NULL;
1229a1bf3f78SToomas Soome STAILQ_FOREACH(cmdp, &commands, next) {
1230a1bf3f78SToomas Soome if (res)
1231a1bf3f78SToomas Soome break;
1232a1bf3f78SToomas Soome if ((cmdp->c_name != NULL) && (cmdp->c_desc != NULL)) {
1233a1bf3f78SToomas Soome sprintf(name, " %-15s ", cmdp->c_name);
1234a1bf3f78SToomas Soome pager_output(name);
1235a1bf3f78SToomas Soome pager_output(cmdp->c_desc);
1236a1bf3f78SToomas Soome res = pager_output("\n");
1237a1bf3f78SToomas Soome }
1238a1bf3f78SToomas Soome }
1239a1bf3f78SToomas Soome pager_close();
1240a1bf3f78SToomas Soome return (CMD_OK);
1241a1bf3f78SToomas Soome }
1242a1bf3f78SToomas Soome
1243a1bf3f78SToomas Soome /*
1244a1bf3f78SToomas Soome * XXX set/show should become set/echo if we have variable
1245a1bf3f78SToomas Soome * substitution happening.
1246a1bf3f78SToomas Soome */
1247a1bf3f78SToomas Soome static int
command_show(int argc,char * argv[])1248a1bf3f78SToomas Soome command_show(int argc, char *argv[])
1249a1bf3f78SToomas Soome {
1250a1bf3f78SToomas Soome char **ev;
1251a1bf3f78SToomas Soome char *cp;
1252a1bf3f78SToomas Soome
1253a1bf3f78SToomas Soome if (argc < 2) {
1254a1bf3f78SToomas Soome /*
1255a1bf3f78SToomas Soome * With no arguments, print everything.
1256a1bf3f78SToomas Soome */
1257a1bf3f78SToomas Soome pager_open();
1258a1bf3f78SToomas Soome for (ev = _environ; *ev != NULL; ev++) {
1259a1bf3f78SToomas Soome pager_output(*ev);
1260a1bf3f78SToomas Soome cp = getenv(*ev);
1261a1bf3f78SToomas Soome if (cp != NULL) {
1262a1bf3f78SToomas Soome pager_output("=");
1263a1bf3f78SToomas Soome pager_output(cp);
1264a1bf3f78SToomas Soome }
1265a1bf3f78SToomas Soome if (pager_output("\n"))
1266a1bf3f78SToomas Soome break;
1267a1bf3f78SToomas Soome }
1268a1bf3f78SToomas Soome pager_close();
1269a1bf3f78SToomas Soome } else {
1270a1bf3f78SToomas Soome if ((cp = getenv(argv[1])) != NULL) {
1271a1bf3f78SToomas Soome printf("%s\n", cp);
1272a1bf3f78SToomas Soome } else {
1273a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1274a1bf3f78SToomas Soome "variable '%s' not found", argv[1]);
1275a1bf3f78SToomas Soome return (CMD_ERROR);
1276a1bf3f78SToomas Soome }
1277a1bf3f78SToomas Soome }
1278a1bf3f78SToomas Soome return (CMD_OK);
1279a1bf3f78SToomas Soome }
1280a1bf3f78SToomas Soome
1281a1bf3f78SToomas Soome static int
command_set(int argc,char * argv[])1282a1bf3f78SToomas Soome command_set(int argc, char *argv[])
1283a1bf3f78SToomas Soome {
1284a1bf3f78SToomas Soome int err;
1285a1bf3f78SToomas Soome char *value, *copy;
1286a1bf3f78SToomas Soome
1287a1bf3f78SToomas Soome if (argc != 2) {
1288a1bf3f78SToomas Soome command_errmsg = "wrong number of arguments";
1289a1bf3f78SToomas Soome return (CMD_ERROR);
1290a1bf3f78SToomas Soome } else {
1291a1bf3f78SToomas Soome copy = strdup(argv[1]);
1292a1bf3f78SToomas Soome if (copy == NULL) {
1293a1bf3f78SToomas Soome command_errmsg = strerror(errno);
1294a1bf3f78SToomas Soome return (CMD_ERROR);
1295a1bf3f78SToomas Soome }
1296a1bf3f78SToomas Soome if ((value = strchr(copy, '=')) != NULL)
1297a1bf3f78SToomas Soome *(value++) = 0;
1298a1bf3f78SToomas Soome else
1299a1bf3f78SToomas Soome value = "";
1300a1bf3f78SToomas Soome if ((err = setenv(copy, value, 1)) != 0) {
1301a1bf3f78SToomas Soome free(copy);
1302a1bf3f78SToomas Soome command_errmsg = strerror(errno);
1303a1bf3f78SToomas Soome return (CMD_ERROR);
1304a1bf3f78SToomas Soome }
1305a1bf3f78SToomas Soome free(copy);
1306a1bf3f78SToomas Soome }
1307a1bf3f78SToomas Soome return (CMD_OK);
1308a1bf3f78SToomas Soome }
1309a1bf3f78SToomas Soome
1310a1bf3f78SToomas Soome static int
command_setprop(int argc,char * argv[])1311a1bf3f78SToomas Soome command_setprop(int argc, char *argv[])
1312a1bf3f78SToomas Soome {
1313a1bf3f78SToomas Soome int err;
1314a1bf3f78SToomas Soome
1315a1bf3f78SToomas Soome if (argc != 3) {
1316a1bf3f78SToomas Soome command_errmsg = "wrong number of arguments";
1317a1bf3f78SToomas Soome return (CMD_ERROR);
1318a1bf3f78SToomas Soome } else {
1319a1bf3f78SToomas Soome if ((err = setenv(argv[1], argv[2], 1)) != 0) {
1320a1bf3f78SToomas Soome command_errmsg = strerror(err);
1321a1bf3f78SToomas Soome return (CMD_ERROR);
1322a1bf3f78SToomas Soome }
1323a1bf3f78SToomas Soome }
1324a1bf3f78SToomas Soome return (CMD_OK);
1325a1bf3f78SToomas Soome }
1326a1bf3f78SToomas Soome
1327a1bf3f78SToomas Soome static int
command_unset(int argc,char * argv[])1328a1bf3f78SToomas Soome command_unset(int argc, char *argv[])
1329a1bf3f78SToomas Soome {
1330a1bf3f78SToomas Soome int err;
1331a1bf3f78SToomas Soome
1332a1bf3f78SToomas Soome if (argc != 2) {
1333a1bf3f78SToomas Soome command_errmsg = "wrong number of arguments";
1334a1bf3f78SToomas Soome return (CMD_ERROR);
1335a1bf3f78SToomas Soome } else {
1336a1bf3f78SToomas Soome if ((err = unsetenv(argv[1])) != 0) {
1337a1bf3f78SToomas Soome command_errmsg = strerror(err);
1338a1bf3f78SToomas Soome return (CMD_ERROR);
1339a1bf3f78SToomas Soome }
1340a1bf3f78SToomas Soome }
1341a1bf3f78SToomas Soome return (CMD_OK);
1342a1bf3f78SToomas Soome }
1343a1bf3f78SToomas Soome
1344a1bf3f78SToomas Soome static int
command_echo(int argc,char * argv[])1345a1bf3f78SToomas Soome command_echo(int argc, char *argv[])
1346a1bf3f78SToomas Soome {
1347a1bf3f78SToomas Soome char *s;
1348a1bf3f78SToomas Soome int nl, ch;
1349a1bf3f78SToomas Soome
1350a1bf3f78SToomas Soome nl = 0;
1351a1bf3f78SToomas Soome optind = 1;
1352a1bf3f78SToomas Soome opterr = 1;
1353a1bf3f78SToomas Soome while ((ch = getopt(argc, argv, "n")) != -1) {
1354a1bf3f78SToomas Soome switch (ch) {
1355a1bf3f78SToomas Soome case 'n':
1356a1bf3f78SToomas Soome nl = 1;
1357a1bf3f78SToomas Soome break;
1358a1bf3f78SToomas Soome case '?':
1359a1bf3f78SToomas Soome default:
1360a1bf3f78SToomas Soome /* getopt has already reported an error */
1361a1bf3f78SToomas Soome return (CMD_OK);
1362a1bf3f78SToomas Soome }
1363a1bf3f78SToomas Soome }
1364a1bf3f78SToomas Soome argv += (optind);
1365a1bf3f78SToomas Soome argc -= (optind);
1366a1bf3f78SToomas Soome
1367a1bf3f78SToomas Soome s = unargv(argc, argv);
1368a1bf3f78SToomas Soome if (s != NULL) {
1369a1bf3f78SToomas Soome printf("%s", s);
1370a1bf3f78SToomas Soome free(s);
1371a1bf3f78SToomas Soome }
1372a1bf3f78SToomas Soome if (!nl)
1373a1bf3f78SToomas Soome printf("\n");
1374a1bf3f78SToomas Soome return (CMD_OK);
1375a1bf3f78SToomas Soome }
1376a1bf3f78SToomas Soome
1377a1bf3f78SToomas Soome /*
1378a1bf3f78SToomas Soome * A passable emulation of the sh(1) command of the same name.
1379a1bf3f78SToomas Soome */
1380a1bf3f78SToomas Soome static int
ischar(void)1381a1bf3f78SToomas Soome ischar(void)
1382a1bf3f78SToomas Soome {
1383a1bf3f78SToomas Soome return (1);
1384a1bf3f78SToomas Soome }
1385a1bf3f78SToomas Soome
1386a1bf3f78SToomas Soome static int
command_read(int argc,char * argv[])1387a1bf3f78SToomas Soome command_read(int argc, char *argv[])
1388a1bf3f78SToomas Soome {
1389a1bf3f78SToomas Soome char *prompt;
1390a1bf3f78SToomas Soome int timeout;
1391a1bf3f78SToomas Soome time_t when;
1392a1bf3f78SToomas Soome char *cp;
1393a1bf3f78SToomas Soome char *name;
1394a1bf3f78SToomas Soome char buf[256]; /* XXX size? */
1395a1bf3f78SToomas Soome int c;
1396a1bf3f78SToomas Soome
1397a1bf3f78SToomas Soome timeout = -1;
1398a1bf3f78SToomas Soome prompt = NULL;
1399a1bf3f78SToomas Soome optind = 1;
1400a1bf3f78SToomas Soome opterr = 1;
1401a1bf3f78SToomas Soome while ((c = getopt(argc, argv, "p:t:")) != -1) {
1402a1bf3f78SToomas Soome switch (c) {
1403a1bf3f78SToomas Soome case 'p':
1404a1bf3f78SToomas Soome prompt = optarg;
1405a1bf3f78SToomas Soome break;
1406a1bf3f78SToomas Soome case 't':
1407a1bf3f78SToomas Soome timeout = strtol(optarg, &cp, 0);
1408a1bf3f78SToomas Soome if (cp == optarg) {
1409a1bf3f78SToomas Soome snprintf(command_errbuf,
1410a1bf3f78SToomas Soome sizeof (command_errbuf),
1411a1bf3f78SToomas Soome "bad timeout '%s'", optarg);
1412a1bf3f78SToomas Soome return (CMD_ERROR);
1413a1bf3f78SToomas Soome }
1414a1bf3f78SToomas Soome break;
1415a1bf3f78SToomas Soome default:
1416a1bf3f78SToomas Soome return (CMD_OK);
1417a1bf3f78SToomas Soome }
1418a1bf3f78SToomas Soome }
1419a1bf3f78SToomas Soome
1420a1bf3f78SToomas Soome argv += (optind);
1421a1bf3f78SToomas Soome argc -= (optind);
1422a1bf3f78SToomas Soome name = (argc > 0) ? argv[0]: NULL;
1423a1bf3f78SToomas Soome
1424a1bf3f78SToomas Soome if (prompt != NULL)
1425a1bf3f78SToomas Soome printf("%s", prompt);
1426a1bf3f78SToomas Soome if (timeout >= 0) {
1427a1bf3f78SToomas Soome when = time(NULL) + timeout;
1428a1bf3f78SToomas Soome while (!ischar())
1429a1bf3f78SToomas Soome if (time(NULL) >= when)
1430a1bf3f78SToomas Soome return (CMD_OK); /* is timeout an error? */
1431a1bf3f78SToomas Soome }
1432a1bf3f78SToomas Soome
1433a1bf3f78SToomas Soome ngets(buf, sizeof (buf));
1434a1bf3f78SToomas Soome
1435a1bf3f78SToomas Soome if (name != NULL)
1436a1bf3f78SToomas Soome setenv(name, buf, 1);
1437a1bf3f78SToomas Soome return (CMD_OK);
1438a1bf3f78SToomas Soome }
1439a1bf3f78SToomas Soome
1440a1bf3f78SToomas Soome /*
1441a1bf3f78SToomas Soome * File pager
1442a1bf3f78SToomas Soome */
1443a1bf3f78SToomas Soome static int
command_more(int argc,char * argv[])1444a1bf3f78SToomas Soome command_more(int argc, char *argv[])
1445a1bf3f78SToomas Soome {
1446a1bf3f78SToomas Soome int i;
1447a1bf3f78SToomas Soome int res;
1448a1bf3f78SToomas Soome char line[80];
1449a1bf3f78SToomas Soome char *name;
1450a1bf3f78SToomas Soome
1451a1bf3f78SToomas Soome res = 0;
1452a1bf3f78SToomas Soome pager_open();
1453a1bf3f78SToomas Soome for (i = 1; (i < argc) && (res == 0); i++) {
1454a1bf3f78SToomas Soome sprintf(line, "*** FILE %s BEGIN ***\n", argv[i]);
1455a1bf3f78SToomas Soome if (pager_output(line))
1456a1bf3f78SToomas Soome break;
1457a1bf3f78SToomas Soome name = get_dev(argv[i]);
1458a1bf3f78SToomas Soome res = page_file(name);
1459a1bf3f78SToomas Soome free(name);
1460a1bf3f78SToomas Soome if (!res) {
1461a1bf3f78SToomas Soome sprintf(line, "*** FILE %s END ***\n", argv[i]);
1462a1bf3f78SToomas Soome res = pager_output(line);
1463a1bf3f78SToomas Soome }
1464a1bf3f78SToomas Soome }
1465a1bf3f78SToomas Soome pager_close();
1466a1bf3f78SToomas Soome
1467a1bf3f78SToomas Soome if (res == 0)
1468a1bf3f78SToomas Soome return (CMD_OK);
1469a1bf3f78SToomas Soome return (CMD_ERROR);
1470a1bf3f78SToomas Soome }
1471a1bf3f78SToomas Soome
1472a1bf3f78SToomas Soome static int
page_file(char * filename)1473a1bf3f78SToomas Soome page_file(char *filename)
1474a1bf3f78SToomas Soome {
1475a1bf3f78SToomas Soome int result;
1476a1bf3f78SToomas Soome
1477a1bf3f78SToomas Soome result = pager_file(filename);
1478a1bf3f78SToomas Soome
1479a1bf3f78SToomas Soome if (result == -1) {
1480a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1481a1bf3f78SToomas Soome "error showing %s", filename);
1482a1bf3f78SToomas Soome }
1483a1bf3f78SToomas Soome
1484a1bf3f78SToomas Soome return (result);
1485a1bf3f78SToomas Soome }
1486a1bf3f78SToomas Soome
1487a1bf3f78SToomas Soome static int
command_ls(int argc,char * argv[])1488a1bf3f78SToomas Soome command_ls(int argc, char *argv[])
1489a1bf3f78SToomas Soome {
1490a1bf3f78SToomas Soome DIR *dir;
1491a1bf3f78SToomas Soome int fd;
1492a1bf3f78SToomas Soome struct stat sb;
1493a1bf3f78SToomas Soome struct dirent *d;
1494a1bf3f78SToomas Soome char *buf, *path;
1495a1bf3f78SToomas Soome char lbuf[128]; /* one line */
1496a1bf3f78SToomas Soome int result, ch;
1497a1bf3f78SToomas Soome int verbose;
1498a1bf3f78SToomas Soome
1499a1bf3f78SToomas Soome result = CMD_OK;
1500a1bf3f78SToomas Soome fd = -1;
1501a1bf3f78SToomas Soome verbose = 0;
1502a1bf3f78SToomas Soome optind = 1;
1503a1bf3f78SToomas Soome opterr = 1;
1504a1bf3f78SToomas Soome while ((ch = getopt(argc, argv, "l")) != -1) {
1505a1bf3f78SToomas Soome switch (ch) {
1506a1bf3f78SToomas Soome case 'l':
1507a1bf3f78SToomas Soome verbose = 1;
1508a1bf3f78SToomas Soome break;
1509a1bf3f78SToomas Soome case '?':
1510a1bf3f78SToomas Soome default:
1511a1bf3f78SToomas Soome /* getopt has already reported an error */
1512a1bf3f78SToomas Soome return (CMD_OK);
1513a1bf3f78SToomas Soome }
1514a1bf3f78SToomas Soome }
1515a1bf3f78SToomas Soome argv += (optind - 1);
1516a1bf3f78SToomas Soome argc -= (optind - 1);
1517a1bf3f78SToomas Soome
1518a1bf3f78SToomas Soome if (argc < 2) {
1519a1bf3f78SToomas Soome path = "";
1520a1bf3f78SToomas Soome } else {
1521a1bf3f78SToomas Soome path = argv[1];
1522a1bf3f78SToomas Soome }
1523a1bf3f78SToomas Soome
1524a1bf3f78SToomas Soome fd = ls_getdir(&path);
1525a1bf3f78SToomas Soome if (fd == -1) {
1526a1bf3f78SToomas Soome result = CMD_ERROR;
1527a1bf3f78SToomas Soome goto out;
1528a1bf3f78SToomas Soome }
1529a1bf3f78SToomas Soome dir = fdopendir(fd);
1530a1bf3f78SToomas Soome pager_open();
1531a1bf3f78SToomas Soome pager_output(path);
1532a1bf3f78SToomas Soome pager_output("\n");
1533a1bf3f78SToomas Soome
1534a1bf3f78SToomas Soome while ((d = readdir(dir)) != NULL) {
1535a1bf3f78SToomas Soome if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) {
1536a1bf3f78SToomas Soome /* stat the file, if possible */
1537a1bf3f78SToomas Soome sb.st_size = 0;
1538a1bf3f78SToomas Soome sb.st_mode = 0;
1539a1bf3f78SToomas Soome buf = malloc(strlen(path) + strlen(d->d_name) + 2);
1540a1bf3f78SToomas Soome if (path[0] == '\0')
1541a1bf3f78SToomas Soome sprintf(buf, "%s", d->d_name);
1542a1bf3f78SToomas Soome else
1543a1bf3f78SToomas Soome sprintf(buf, "%s/%s", path, d->d_name);
1544a1bf3f78SToomas Soome /* ignore return, could be symlink, etc. */
1545a1bf3f78SToomas Soome if (stat(buf, &sb))
1546a1bf3f78SToomas Soome sb.st_size = 0;
1547a1bf3f78SToomas Soome free(buf);
1548a1bf3f78SToomas Soome if (verbose) {
1549a1bf3f78SToomas Soome sprintf(lbuf, " %c %8d %s\n",
1550a1bf3f78SToomas Soome typestr[sb.st_mode >> 12],
1551a1bf3f78SToomas Soome (int)sb.st_size, d->d_name);
1552a1bf3f78SToomas Soome } else {
1553a1bf3f78SToomas Soome sprintf(lbuf, " %c %s\n",
1554a1bf3f78SToomas Soome typestr[sb.st_mode >> 12], d->d_name);
1555a1bf3f78SToomas Soome }
1556a1bf3f78SToomas Soome if (pager_output(lbuf))
1557a1bf3f78SToomas Soome goto out;
1558a1bf3f78SToomas Soome }
1559a1bf3f78SToomas Soome }
1560a1bf3f78SToomas Soome out:
1561a1bf3f78SToomas Soome pager_close();
1562a1bf3f78SToomas Soome if (fd != -1)
1563a1bf3f78SToomas Soome closedir(dir);
1564a1bf3f78SToomas Soome if (path != NULL)
1565a1bf3f78SToomas Soome free(path);
1566a1bf3f78SToomas Soome return (result);
1567a1bf3f78SToomas Soome }
1568a1bf3f78SToomas Soome
1569a1bf3f78SToomas Soome /*
1570a1bf3f78SToomas Soome * Given (path) containing a vaguely reasonable path specification, return an fd
1571a1bf3f78SToomas Soome * on the directory, and an allocated copy of the path to the directory.
1572a1bf3f78SToomas Soome */
1573a1bf3f78SToomas Soome static int
ls_getdir(char ** pathp)1574a1bf3f78SToomas Soome ls_getdir(char **pathp)
1575a1bf3f78SToomas Soome {
1576a1bf3f78SToomas Soome struct stat sb;
1577a1bf3f78SToomas Soome int fd;
1578a1bf3f78SToomas Soome char *cp, *path;
1579a1bf3f78SToomas Soome
1580a1bf3f78SToomas Soome fd = -1;
1581a1bf3f78SToomas Soome
1582a1bf3f78SToomas Soome /* one extra byte for a possible trailing slash required */
1583a1bf3f78SToomas Soome path = malloc(strlen(*pathp) + 2);
1584a1bf3f78SToomas Soome strcpy(path, *pathp);
1585a1bf3f78SToomas Soome
1586a1bf3f78SToomas Soome /* Make sure the path is respectable to begin with */
1587a1bf3f78SToomas Soome if ((cp = get_dev(path)) == NULL) {
1588a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1589a1bf3f78SToomas Soome "bad path '%s'", path);
1590a1bf3f78SToomas Soome goto out;
1591a1bf3f78SToomas Soome }
1592a1bf3f78SToomas Soome
1593a1bf3f78SToomas Soome /* If there's no path on the device, assume '/' */
1594a1bf3f78SToomas Soome if (*cp == 0)
1595a1bf3f78SToomas Soome strcat(path, "/");
1596a1bf3f78SToomas Soome
1597a1bf3f78SToomas Soome fd = open(cp, O_RDONLY);
1598a1bf3f78SToomas Soome if (fd < 0) {
1599a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1600a1bf3f78SToomas Soome "open '%s' failed: %s", path, strerror(errno));
1601a1bf3f78SToomas Soome goto out;
1602a1bf3f78SToomas Soome }
1603a1bf3f78SToomas Soome if (fstat(fd, &sb) < 0) {
1604a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1605a1bf3f78SToomas Soome "stat failed: %s", strerror(errno));
1606a1bf3f78SToomas Soome goto out;
1607a1bf3f78SToomas Soome }
1608a1bf3f78SToomas Soome if (!S_ISDIR(sb.st_mode)) {
1609a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1610a1bf3f78SToomas Soome "%s: %s", path, strerror(ENOTDIR));
1611a1bf3f78SToomas Soome goto out;
1612a1bf3f78SToomas Soome }
1613a1bf3f78SToomas Soome
1614a1bf3f78SToomas Soome free(cp);
1615a1bf3f78SToomas Soome *pathp = path;
1616a1bf3f78SToomas Soome return (fd);
1617a1bf3f78SToomas Soome
1618a1bf3f78SToomas Soome out:
1619a1bf3f78SToomas Soome free(cp);
1620a1bf3f78SToomas Soome free(path);
1621a1bf3f78SToomas Soome *pathp = NULL;
1622a1bf3f78SToomas Soome if (fd != -1)
1623a1bf3f78SToomas Soome close(fd);
1624a1bf3f78SToomas Soome return (-1);
1625a1bf3f78SToomas Soome }
1626a1bf3f78SToomas Soome
1627a1bf3f78SToomas Soome static int
command_include(int argc,char * argv[])1628a1bf3f78SToomas Soome command_include(int argc, char *argv[])
1629a1bf3f78SToomas Soome {
1630a1bf3f78SToomas Soome int i;
1631a1bf3f78SToomas Soome int res;
1632a1bf3f78SToomas Soome char **argvbuf;
1633a1bf3f78SToomas Soome
1634a1bf3f78SToomas Soome /*
1635a1bf3f78SToomas Soome * Since argv is static, we need to save it here.
1636a1bf3f78SToomas Soome */
1637a1bf3f78SToomas Soome argvbuf = (char **)calloc(argc, sizeof (char *));
1638a1bf3f78SToomas Soome for (i = 0; i < argc; i++)
1639a1bf3f78SToomas Soome argvbuf[i] = strdup(argv[i]);
1640a1bf3f78SToomas Soome
1641a1bf3f78SToomas Soome res = CMD_OK;
1642a1bf3f78SToomas Soome for (i = 1; (i < argc) && (res == CMD_OK); i++)
1643a1bf3f78SToomas Soome res = include(argvbuf[i]);
1644a1bf3f78SToomas Soome
1645a1bf3f78SToomas Soome for (i = 0; i < argc; i++)
1646a1bf3f78SToomas Soome free(argvbuf[i]);
1647a1bf3f78SToomas Soome free(argvbuf);
1648a1bf3f78SToomas Soome
1649a1bf3f78SToomas Soome return (res);
1650a1bf3f78SToomas Soome }
1651a1bf3f78SToomas Soome
1652a1bf3f78SToomas Soome /*
1653a1bf3f78SToomas Soome * Header prepended to each line. The text immediately follows the header.
1654a1bf3f78SToomas Soome * We try to make this short in order to save memory -- the loader has
1655a1bf3f78SToomas Soome * limited memory available, and some of the forth files are very long.
1656a1bf3f78SToomas Soome */
1657a1bf3f78SToomas Soome struct includeline
1658a1bf3f78SToomas Soome {
1659a1bf3f78SToomas Soome struct includeline *next;
1660a1bf3f78SToomas Soome int line;
1661a1bf3f78SToomas Soome char text[];
1662a1bf3f78SToomas Soome };
1663a1bf3f78SToomas Soome
1664a1bf3f78SToomas Soome int
include(const char * filename)1665a1bf3f78SToomas Soome include(const char *filename)
1666a1bf3f78SToomas Soome {
1667a1bf3f78SToomas Soome struct includeline *script, *se, *sp;
1668a1bf3f78SToomas Soome int res = CMD_OK;
1669a1bf3f78SToomas Soome int prevsrcid, fd, line;
1670a1bf3f78SToomas Soome char *cp, input[256]; /* big enough? */
1671a1bf3f78SToomas Soome char *path;
1672a1bf3f78SToomas Soome
1673a1bf3f78SToomas Soome path = get_dev(filename);
1674a1bf3f78SToomas Soome if (((fd = open(path, O_RDONLY)) == -1)) {
1675a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1676a1bf3f78SToomas Soome "can't open '%s': %s", filename,
1677a1bf3f78SToomas Soome strerror(errno));
1678a1bf3f78SToomas Soome free(path);
1679a1bf3f78SToomas Soome return (CMD_ERROR);
1680a1bf3f78SToomas Soome }
1681a1bf3f78SToomas Soome
1682a1bf3f78SToomas Soome free(path);
1683a1bf3f78SToomas Soome /*
1684a1bf3f78SToomas Soome * Read the script into memory.
1685a1bf3f78SToomas Soome */
1686a1bf3f78SToomas Soome script = se = NULL;
1687a1bf3f78SToomas Soome line = 0;
1688a1bf3f78SToomas Soome
1689a1bf3f78SToomas Soome while (fgetstr(input, sizeof (input), fd) >= 0) {
1690a1bf3f78SToomas Soome line++;
1691a1bf3f78SToomas Soome cp = input;
1692a1bf3f78SToomas Soome /* Allocate script line structure and copy line, flags */
1693a1bf3f78SToomas Soome if (*cp == '\0')
1694a1bf3f78SToomas Soome continue; /* ignore empty line, save memory */
1695a1bf3f78SToomas Soome if (cp[0] == '\\' && cp[1] == ' ')
1696a1bf3f78SToomas Soome continue; /* ignore comment */
1697a1bf3f78SToomas Soome
1698a1bf3f78SToomas Soome sp = malloc(sizeof (struct includeline) + strlen(cp) + 1);
1699a1bf3f78SToomas Soome /*
1700a1bf3f78SToomas Soome * On malloc failure (it happens!), free as much as possible
1701a1bf3f78SToomas Soome * and exit
1702a1bf3f78SToomas Soome */
1703a1bf3f78SToomas Soome if (sp == NULL) {
1704a1bf3f78SToomas Soome while (script != NULL) {
1705a1bf3f78SToomas Soome se = script;
1706a1bf3f78SToomas Soome script = script->next;
1707a1bf3f78SToomas Soome free(se);
1708a1bf3f78SToomas Soome }
1709a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1710a1bf3f78SToomas Soome "file '%s' line %d: memory allocation "
1711a1bf3f78SToomas Soome "failure - aborting", filename, line);
1712a1bf3f78SToomas Soome return (CMD_ERROR);
1713a1bf3f78SToomas Soome }
1714a1bf3f78SToomas Soome strcpy(sp->text, cp);
1715a1bf3f78SToomas Soome sp->line = line;
1716a1bf3f78SToomas Soome sp->next = NULL;
1717a1bf3f78SToomas Soome
1718a1bf3f78SToomas Soome if (script == NULL) {
1719a1bf3f78SToomas Soome script = sp;
1720a1bf3f78SToomas Soome } else {
1721a1bf3f78SToomas Soome se->next = sp;
1722a1bf3f78SToomas Soome }
1723a1bf3f78SToomas Soome se = sp;
1724a1bf3f78SToomas Soome }
1725a1bf3f78SToomas Soome close(fd);
1726a1bf3f78SToomas Soome
1727a1bf3f78SToomas Soome /*
1728a1bf3f78SToomas Soome * Execute the script
1729a1bf3f78SToomas Soome */
1730a1bf3f78SToomas Soome
1731a1bf3f78SToomas Soome prevsrcid = bf_vm->sourceId.i;
1732a1bf3f78SToomas Soome bf_vm->sourceId.i = fd+1; /* 0 is user input device */
1733a1bf3f78SToomas Soome
1734a1bf3f78SToomas Soome res = CMD_OK;
1735a1bf3f78SToomas Soome
1736a1bf3f78SToomas Soome for (sp = script; sp != NULL; sp = sp->next) {
1737a1bf3f78SToomas Soome res = bf_run(sp->text);
1738a1bf3f78SToomas Soome if (res != FICL_VM_STATUS_OUT_OF_TEXT) {
1739a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1740a1bf3f78SToomas Soome "Error while including %s, in the line %d:\n%s",
1741a1bf3f78SToomas Soome filename, sp->line, sp->text);
1742a1bf3f78SToomas Soome res = CMD_ERROR;
1743a1bf3f78SToomas Soome break;
1744a1bf3f78SToomas Soome } else
1745a1bf3f78SToomas Soome res = CMD_OK;
1746a1bf3f78SToomas Soome }
1747a1bf3f78SToomas Soome
1748a1bf3f78SToomas Soome bf_vm->sourceId.i = -1;
1749a1bf3f78SToomas Soome (void) bf_run("");
1750a1bf3f78SToomas Soome bf_vm->sourceId.i = prevsrcid;
1751a1bf3f78SToomas Soome
1752a1bf3f78SToomas Soome while (script != NULL) {
1753a1bf3f78SToomas Soome se = script;
1754a1bf3f78SToomas Soome script = script->next;
1755a1bf3f78SToomas Soome free(se);
1756a1bf3f78SToomas Soome }
1757a1bf3f78SToomas Soome
1758a1bf3f78SToomas Soome return (res);
1759a1bf3f78SToomas Soome }
1760a1bf3f78SToomas Soome
1761a1bf3f78SToomas Soome static int
command_boot(int argc,char * argv[])1762a1bf3f78SToomas Soome command_boot(int argc, char *argv[])
1763a1bf3f78SToomas Soome {
1764a1bf3f78SToomas Soome return (CMD_OK);
1765a1bf3f78SToomas Soome }
1766a1bf3f78SToomas Soome
1767a1bf3f78SToomas Soome static int
command_autoboot(int argc,char * argv[])1768a1bf3f78SToomas Soome command_autoboot(int argc, char *argv[])
1769a1bf3f78SToomas Soome {
1770a1bf3f78SToomas Soome return (CMD_OK);
1771a1bf3f78SToomas Soome }
1772a1bf3f78SToomas Soome
1773a1bf3f78SToomas Soome static void
moduledir_rebuild(void)1774a1bf3f78SToomas Soome moduledir_rebuild(void)
1775a1bf3f78SToomas Soome {
1776a1bf3f78SToomas Soome struct moduledir *mdp, *mtmp;
1777a1bf3f78SToomas Soome const char *path, *cp, *ep;
1778a1bf3f78SToomas Soome int cplen;
1779a1bf3f78SToomas Soome
1780a1bf3f78SToomas Soome path = getenv("module_path");
1781a1bf3f78SToomas Soome if (path == NULL)
1782a1bf3f78SToomas Soome path = default_searchpath;
1783a1bf3f78SToomas Soome /*
1784a1bf3f78SToomas Soome * Rebuild list of module directories if it changed
1785a1bf3f78SToomas Soome */
1786a1bf3f78SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link)
1787a1bf3f78SToomas Soome mdp->d_flags |= MDIR_REMOVED;
1788a1bf3f78SToomas Soome
1789a1bf3f78SToomas Soome for (ep = path; *ep != 0; ep++) {
1790a1bf3f78SToomas Soome cp = ep;
1791a1bf3f78SToomas Soome for (; *ep != 0 && *ep != ';'; ep++)
1792a1bf3f78SToomas Soome ;
1793a1bf3f78SToomas Soome /*
1794a1bf3f78SToomas Soome * Ignore trailing slashes
1795a1bf3f78SToomas Soome */
1796a1bf3f78SToomas Soome for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/';
1797a1bf3f78SToomas Soome cplen--)
1798a1bf3f78SToomas Soome ;
1799a1bf3f78SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1800a1bf3f78SToomas Soome if (strlen(mdp->d_path) != cplen ||
1801a1bf3f78SToomas Soome bcmp(cp, mdp->d_path, cplen) != 0)
1802a1bf3f78SToomas Soome continue;
1803a1bf3f78SToomas Soome mdp->d_flags &= ~MDIR_REMOVED;
1804a1bf3f78SToomas Soome break;
1805a1bf3f78SToomas Soome }
1806a1bf3f78SToomas Soome if (mdp == NULL) {
1807a1bf3f78SToomas Soome mdp = malloc(sizeof (*mdp) + cplen + 1);
1808a1bf3f78SToomas Soome if (mdp == NULL)
1809a1bf3f78SToomas Soome return;
1810a1bf3f78SToomas Soome mdp->d_path = (char *)(mdp + 1);
1811a1bf3f78SToomas Soome bcopy(cp, mdp->d_path, cplen);
1812a1bf3f78SToomas Soome mdp->d_path[cplen] = 0;
1813a1bf3f78SToomas Soome mdp->d_hints = NULL;
1814a1bf3f78SToomas Soome mdp->d_flags = 0;
1815a1bf3f78SToomas Soome STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
1816a1bf3f78SToomas Soome }
1817a1bf3f78SToomas Soome if (*ep == 0)
1818a1bf3f78SToomas Soome break;
1819a1bf3f78SToomas Soome }
1820a1bf3f78SToomas Soome /*
1821a1bf3f78SToomas Soome * Delete unused directories if any
1822a1bf3f78SToomas Soome */
1823a1bf3f78SToomas Soome mdp = STAILQ_FIRST(&moduledir_list);
1824a1bf3f78SToomas Soome while (mdp) {
1825a1bf3f78SToomas Soome if ((mdp->d_flags & MDIR_REMOVED) == 0) {
1826a1bf3f78SToomas Soome mdp = STAILQ_NEXT(mdp, d_link);
1827a1bf3f78SToomas Soome } else {
1828a1bf3f78SToomas Soome if (mdp->d_hints)
1829a1bf3f78SToomas Soome free(mdp->d_hints);
1830a1bf3f78SToomas Soome mtmp = mdp;
1831a1bf3f78SToomas Soome mdp = STAILQ_NEXT(mdp, d_link);
1832a1bf3f78SToomas Soome STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
1833a1bf3f78SToomas Soome free(mtmp);
1834a1bf3f78SToomas Soome }
1835a1bf3f78SToomas Soome }
1836a1bf3f78SToomas Soome }
1837a1bf3f78SToomas Soome
1838a1bf3f78SToomas Soome static char *
file_lookup(const char * path,const char * name,int namelen)1839a1bf3f78SToomas Soome file_lookup(const char *path, const char *name, int namelen)
1840a1bf3f78SToomas Soome {
1841a1bf3f78SToomas Soome struct stat st;
1842a1bf3f78SToomas Soome char *result, *cp, *gz;
1843a1bf3f78SToomas Soome int pathlen;
1844a1bf3f78SToomas Soome
1845a1bf3f78SToomas Soome pathlen = strlen(path);
1846a1bf3f78SToomas Soome result = malloc(pathlen + namelen + 2);
1847a1bf3f78SToomas Soome if (result == NULL)
1848a1bf3f78SToomas Soome return (NULL);
1849a1bf3f78SToomas Soome bcopy(path, result, pathlen);
1850a1bf3f78SToomas Soome if (pathlen > 0 && result[pathlen - 1] != '/')
1851a1bf3f78SToomas Soome result[pathlen++] = '/';
1852a1bf3f78SToomas Soome cp = result + pathlen;
1853a1bf3f78SToomas Soome bcopy(name, cp, namelen);
1854a1bf3f78SToomas Soome cp += namelen;
1855a1bf3f78SToomas Soome *cp = '\0';
1856a1bf3f78SToomas Soome if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
1857a1bf3f78SToomas Soome return (result);
1858a1bf3f78SToomas Soome /* also check for gz file */
1859a1bf3f78SToomas Soome (void) asprintf(&gz, "%s.gz", result);
1860a1bf3f78SToomas Soome if (gz != NULL) {
1861a1bf3f78SToomas Soome int res = stat(gz, &st);
1862a1bf3f78SToomas Soome free(gz);
1863a1bf3f78SToomas Soome if (res == 0)
1864a1bf3f78SToomas Soome return (result);
1865a1bf3f78SToomas Soome }
1866a1bf3f78SToomas Soome free(result);
1867a1bf3f78SToomas Soome return (NULL);
1868a1bf3f78SToomas Soome }
1869a1bf3f78SToomas Soome
1870a1bf3f78SToomas Soome static char *
file_search(const char * name)1871a1bf3f78SToomas Soome file_search(const char *name)
1872a1bf3f78SToomas Soome {
1873a1bf3f78SToomas Soome struct moduledir *mdp;
1874a1bf3f78SToomas Soome struct stat sb;
1875a1bf3f78SToomas Soome char *result;
1876a1bf3f78SToomas Soome int namelen;
1877a1bf3f78SToomas Soome
1878a1bf3f78SToomas Soome if (name == NULL)
1879a1bf3f78SToomas Soome return (NULL);
1880a1bf3f78SToomas Soome if (*name == 0)
1881a1bf3f78SToomas Soome return (strdup(name));
1882a1bf3f78SToomas Soome
1883a1bf3f78SToomas Soome if (strchr(name, '/') != NULL) {
1884a1bf3f78SToomas Soome char *gz;
1885a1bf3f78SToomas Soome if (stat(name, &sb) == 0)
1886a1bf3f78SToomas Soome return (strdup(name));
1887a1bf3f78SToomas Soome /* also check for gz file */
1888a1bf3f78SToomas Soome (void) asprintf(&gz, "%s.gz", name);
1889a1bf3f78SToomas Soome if (gz != NULL) {
1890a1bf3f78SToomas Soome int res = stat(gz, &sb);
1891a1bf3f78SToomas Soome free(gz);
1892a1bf3f78SToomas Soome if (res == 0)
1893a1bf3f78SToomas Soome return (strdup(name));
1894a1bf3f78SToomas Soome }
1895a1bf3f78SToomas Soome return (NULL);
1896a1bf3f78SToomas Soome }
1897a1bf3f78SToomas Soome
1898a1bf3f78SToomas Soome moduledir_rebuild();
1899a1bf3f78SToomas Soome result = NULL;
1900a1bf3f78SToomas Soome namelen = strlen(name);
1901a1bf3f78SToomas Soome STAILQ_FOREACH(mdp, &moduledir_list, d_link) {
1902a1bf3f78SToomas Soome result = file_lookup(mdp->d_path, name, namelen);
1903a1bf3f78SToomas Soome if (result)
1904a1bf3f78SToomas Soome break;
1905a1bf3f78SToomas Soome }
1906a1bf3f78SToomas Soome return (result);
1907a1bf3f78SToomas Soome }
1908a1bf3f78SToomas Soome
1909a1bf3f78SToomas Soome static int
command_load(int argc,char * argv[])1910a1bf3f78SToomas Soome command_load(int argc, char *argv[])
1911a1bf3f78SToomas Soome {
1912a1bf3f78SToomas Soome int dofile, ch;
1913a1bf3f78SToomas Soome char *typestr = NULL;
1914a1bf3f78SToomas Soome char *filename;
1915a1bf3f78SToomas Soome dofile = 0;
1916a1bf3f78SToomas Soome optind = 1;
1917a1bf3f78SToomas Soome
1918a1bf3f78SToomas Soome if (argc == 1) {
1919a1bf3f78SToomas Soome command_errmsg = "no filename specified";
1920a1bf3f78SToomas Soome return (CMD_ERROR);
1921a1bf3f78SToomas Soome }
1922a1bf3f78SToomas Soome
1923a1bf3f78SToomas Soome while ((ch = getopt(argc, argv, "kt:")) != -1) {
1924a1bf3f78SToomas Soome switch (ch) {
1925a1bf3f78SToomas Soome case 'k':
1926a1bf3f78SToomas Soome break;
1927a1bf3f78SToomas Soome case 't':
1928a1bf3f78SToomas Soome typestr = optarg;
1929a1bf3f78SToomas Soome dofile = 1;
1930a1bf3f78SToomas Soome break;
1931a1bf3f78SToomas Soome case '?':
1932a1bf3f78SToomas Soome default:
1933a1bf3f78SToomas Soome return (CMD_OK);
1934a1bf3f78SToomas Soome }
1935a1bf3f78SToomas Soome }
1936a1bf3f78SToomas Soome argv += (optind - 1);
1937a1bf3f78SToomas Soome argc -= (optind - 1);
1938a1bf3f78SToomas Soome if (dofile) {
1939a1bf3f78SToomas Soome if ((typestr == NULL) || (*typestr == 0)) {
1940a1bf3f78SToomas Soome command_errmsg = "invalid load type";
1941a1bf3f78SToomas Soome return (CMD_ERROR);
1942a1bf3f78SToomas Soome }
1943a1bf3f78SToomas Soome #if 0
1944a1bf3f78SToomas Soome return (file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1)
1945a1bf3f78SToomas Soome ? CMD_OK : CMD_ERROR);
1946a1bf3f78SToomas Soome #endif
1947a1bf3f78SToomas Soome return (CMD_OK);
1948a1bf3f78SToomas Soome }
1949a1bf3f78SToomas Soome
1950a1bf3f78SToomas Soome filename = file_search(argv[1]);
1951a1bf3f78SToomas Soome if (filename == NULL) {
1952a1bf3f78SToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
1953a1bf3f78SToomas Soome "can't find '%s'", argv[1]);
1954a1bf3f78SToomas Soome return (CMD_ERROR);
1955a1bf3f78SToomas Soome }
1956a1bf3f78SToomas Soome setenv("kernelname", filename, 1);
1957a1bf3f78SToomas Soome
1958a1bf3f78SToomas Soome return (CMD_OK);
1959a1bf3f78SToomas Soome }
1960a1bf3f78SToomas Soome
1961a1bf3f78SToomas Soome static int
command_unload(int argc,char * argv[])1962a1bf3f78SToomas Soome command_unload(int argc, char *argv[])
1963a1bf3f78SToomas Soome {
1964a1bf3f78SToomas Soome unsetenv("kernelname");
1965a1bf3f78SToomas Soome return (CMD_OK);
1966a1bf3f78SToomas Soome }
1967a1bf3f78SToomas Soome
1968a1bf3f78SToomas Soome static int
command_reboot(int argc,char * argv[])1969a1bf3f78SToomas Soome command_reboot(int argc, char *argv[])
1970a1bf3f78SToomas Soome {
1971a1bf3f78SToomas Soome exit(0);
1972a1bf3f78SToomas Soome return (CMD_OK);
1973a1bf3f78SToomas Soome }
1974