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