xref: /freebsd/stand/common/commands.c (revision ab08da5328b4175e399d8e59adc4dfad0eea24f1)
1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3ca987d46SWarner Losh  * All rights reserved.
4ca987d46SWarner Losh  *
5ca987d46SWarner Losh  * Redistribution and use in source and binary forms, with or without
6ca987d46SWarner Losh  * modification, are permitted provided that the following conditions
7ca987d46SWarner Losh  * are met:
8ca987d46SWarner Losh  * 1. Redistributions of source code must retain the above copyright
9ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer.
10ca987d46SWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
11ca987d46SWarner Losh  *    notice, this list of conditions and the following disclaimer in the
12ca987d46SWarner Losh  *    documentation and/or other materials provided with the distribution.
13ca987d46SWarner Losh  *
14ca987d46SWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ca987d46SWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ca987d46SWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ca987d46SWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ca987d46SWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ca987d46SWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ca987d46SWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ca987d46SWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ca987d46SWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ca987d46SWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ca987d46SWarner Losh  * SUCH DAMAGE.
25ca987d46SWarner Losh  */
26ca987d46SWarner Losh 
27ca987d46SWarner Losh #include <stand.h>
28ca987d46SWarner Losh #include <string.h>
29ca987d46SWarner Losh 
30ca987d46SWarner Losh #include "bootstrap.h"
31ca987d46SWarner Losh 
32746dddb1SToomas Soome const char	*command_errmsg;
33ca987d46SWarner Losh /* XXX should have procedural interface for setting, size limit? */
34ca987d46SWarner Losh char		command_errbuf[COMMAND_ERRBUFSZ];
35ca987d46SWarner Losh 
36ca987d46SWarner Losh static int page_file(char *filename);
37ca987d46SWarner Losh 
38ca987d46SWarner Losh /*
39ca987d46SWarner Losh  * Help is read from a formatted text file.
40ca987d46SWarner Losh  *
41ca987d46SWarner Losh  * Entries in the file are formatted as
42ca987d46SWarner Losh 
43ca987d46SWarner Losh # Ttopic [Ssubtopic] Ddescription
44ca987d46SWarner Losh help
45ca987d46SWarner Losh text
46ca987d46SWarner Losh here
47ca987d46SWarner Losh #
48ca987d46SWarner Losh 
49ca987d46SWarner Losh  *
50ca987d46SWarner Losh  * Note that for code simplicity's sake, the above format must be followed
51ca987d46SWarner Losh  * exactly.
52ca987d46SWarner Losh  *
53ca987d46SWarner Losh  * Subtopic entries must immediately follow the topic (this is used to
54ca987d46SWarner Losh  * produce the listing of subtopics).
55ca987d46SWarner Losh  *
56ca987d46SWarner Losh  * If no argument(s) are supplied by the user, the help for 'help' is displayed.
57ca987d46SWarner Losh  */
58ca987d46SWarner Losh COMMAND_SET(help, "help", "detailed help", command_help);
59ca987d46SWarner Losh 
60ca987d46SWarner Losh static int
help_getnext(int fd,char ** topic,char ** subtopic,char ** desc)61ca987d46SWarner Losh help_getnext(int fd, char **topic, char **subtopic, char **desc)
62ca987d46SWarner Losh {
63ca987d46SWarner Losh 	char	line[81], *cp, *ep;
64ca987d46SWarner Losh 
655276f604SToomas Soome 	/* Make sure we provide sane values. */
665276f604SToomas Soome 	*topic = *subtopic = *desc = NULL;
67ca987d46SWarner Losh 	for (;;) {
68ca987d46SWarner Losh 		if (fgetstr(line, 80, fd) < 0)
69ca987d46SWarner Losh 			return (0);
70ca987d46SWarner Losh 
71b67d407aSToomas Soome 		if (strlen(line) < 3 || line[0] != '#' || line[1] != ' ')
72ca987d46SWarner Losh 			continue;
73ca987d46SWarner Losh 
74ca987d46SWarner Losh 		cp = line + 2;
75b67d407aSToomas Soome 		while (cp != NULL && *cp != 0) {
76ca987d46SWarner Losh 			ep = strchr(cp, ' ');
77b67d407aSToomas Soome 			if (*cp == 'T' && *topic == NULL) {
78ca987d46SWarner Losh 				if (ep != NULL)
79ca987d46SWarner Losh 					*ep++ = 0;
80ca987d46SWarner Losh 				*topic = strdup(cp + 1);
81b67d407aSToomas Soome 			} else if (*cp == 'S' && *subtopic == NULL) {
82ca987d46SWarner Losh 				if (ep != NULL)
83ca987d46SWarner Losh 					*ep++ = 0;
84ca987d46SWarner Losh 				*subtopic = strdup(cp + 1);
85ca987d46SWarner Losh 			} else if (*cp == 'D') {
86ca987d46SWarner Losh 				*desc = strdup(cp + 1);
87ca987d46SWarner Losh 				ep = NULL;
88ca987d46SWarner Losh 			}
89ca987d46SWarner Losh 			cp = ep;
90ca987d46SWarner Losh 		}
91ca987d46SWarner Losh 		if (*topic == NULL) {
92ca987d46SWarner Losh 			free(*subtopic);
93ca987d46SWarner Losh 			free(*desc);
946d68f8acSToomas Soome 			*subtopic = *desc = NULL;
95ca987d46SWarner Losh 			continue;
96ca987d46SWarner Losh 		}
97ca987d46SWarner Losh 		return (1);
98ca987d46SWarner Losh 	}
99ca987d46SWarner Losh }
100ca987d46SWarner Losh 
101ca987d46SWarner Losh static int
help_emitsummary(char * topic,char * subtopic,char * desc)102ca987d46SWarner Losh help_emitsummary(char *topic, char *subtopic, char *desc)
103ca987d46SWarner Losh {
104ca987d46SWarner Losh 	int	i;
105ca987d46SWarner Losh 
106ca987d46SWarner Losh 	pager_output("    ");
107ca987d46SWarner Losh 	pager_output(topic);
108ca987d46SWarner Losh 	i = strlen(topic);
109ca987d46SWarner Losh 	if (subtopic != NULL) {
110ca987d46SWarner Losh 		pager_output(" ");
111ca987d46SWarner Losh 		pager_output(subtopic);
112ca987d46SWarner Losh 		i += strlen(subtopic) + 1;
113ca987d46SWarner Losh 	}
114ca987d46SWarner Losh 	if (desc != NULL) {
115ca987d46SWarner Losh 		do {
116ca987d46SWarner Losh 			pager_output(" ");
117ca987d46SWarner Losh 		} while (i++ < 30);
118ca987d46SWarner Losh 		pager_output(desc);
119ca987d46SWarner Losh 	}
120ca987d46SWarner Losh 	return (pager_output("\n"));
121ca987d46SWarner Losh }
122ca987d46SWarner Losh 
123ca987d46SWarner Losh static int
command_help(int argc,char * argv[])124ca987d46SWarner Losh command_help(int argc, char *argv[])
125ca987d46SWarner Losh {
126ca987d46SWarner Losh 	char	buf[81];	/* XXX buffer size? */
127ca987d46SWarner Losh 	int	hfd, matched, doindex;
128ca987d46SWarner Losh 	char	*topic, *subtopic, *t, *s, *d;
129ca987d46SWarner Losh 
130ca987d46SWarner Losh 	/* page the help text from our load path */
13188599604SMitchell Horne 	snprintf(buf, sizeof(buf), "%s/boot/%s", getenv("loaddev"),
13288599604SMitchell Horne 	    HELP_FILENAME);
133ca987d46SWarner Losh 	if ((hfd = open(buf, O_RDONLY)) < 0) {
134b67d407aSToomas Soome 		printf("Verbose help not available, "
135b67d407aSToomas Soome 		    "use '?' to list commands\n");
136ca987d46SWarner Losh 		return (CMD_OK);
137ca987d46SWarner Losh 	}
138ca987d46SWarner Losh 
139ca987d46SWarner Losh 	/* pick up request from arguments */
140ca987d46SWarner Losh 	topic = subtopic = NULL;
141ca987d46SWarner Losh 	switch (argc) {
142ca987d46SWarner Losh 	case 3:
143ca987d46SWarner Losh 		subtopic = strdup(argv[2]);
144b67d407aSToomas Soome 		/* FALLTHROUGH */
145ca987d46SWarner Losh 	case 2:
146ca987d46SWarner Losh 		topic = strdup(argv[1]);
147ca987d46SWarner Losh 		break;
148ca987d46SWarner Losh 	case 1:
149ca987d46SWarner Losh 		topic = strdup("help");
150ca987d46SWarner Losh 		break;
151ca987d46SWarner Losh 	default:
152ca987d46SWarner Losh 		command_errmsg = "usage is 'help <topic> [<subtopic>]";
153ca987d46SWarner Losh 		close(hfd);
154ca987d46SWarner Losh 		return(CMD_ERROR);
155ca987d46SWarner Losh 	}
156ca987d46SWarner Losh 
157ca987d46SWarner Losh 	/* magic "index" keyword */
158b67d407aSToomas Soome 	doindex = strcmp(topic, "index") == 0? 1 : 0;
159ca987d46SWarner Losh 	matched = doindex;
160ca987d46SWarner Losh 
161ca987d46SWarner Losh 	/* Scan the helpfile looking for help matching the request */
162ca987d46SWarner Losh 	pager_open();
163ca987d46SWarner Losh 	while (help_getnext(hfd, &t, &s, &d)) {
164ca987d46SWarner Losh 
165ca987d46SWarner Losh 		if (doindex) {		/* dink around formatting */
166ca987d46SWarner Losh 			if (help_emitsummary(t, s, d))
167ca987d46SWarner Losh 				break;
168ca987d46SWarner Losh 
169ca987d46SWarner Losh 		} else if (strcmp(topic, t)) {
170ca987d46SWarner Losh 			/* topic mismatch */
171b67d407aSToomas Soome 			if (matched) {
172b67d407aSToomas Soome 				/* nothing more on this topic, stop scanning */
173ca987d46SWarner Losh 				break;
174b67d407aSToomas Soome 			}
175ca987d46SWarner Losh 		} else {
176ca987d46SWarner Losh 			/* topic matched */
177ca987d46SWarner Losh 			matched = 1;
178b67d407aSToomas Soome 			if ((subtopic == NULL && s == NULL) ||
179b67d407aSToomas Soome 			    (subtopic != NULL && s != NULL &&
180b67d407aSToomas Soome 			    strcmp(subtopic, s) == 0)) {
181ca987d46SWarner Losh 				/* exact match, print text */
182b67d407aSToomas Soome 				while (fgetstr(buf, 80, hfd) >= 0 &&
183b67d407aSToomas Soome 				    buf[0] != '#') {
184ca987d46SWarner Losh 					if (pager_output(buf))
185ca987d46SWarner Losh 						break;
186ca987d46SWarner Losh 					if (pager_output("\n"))
187ca987d46SWarner Losh 						break;
188ca987d46SWarner Losh 				}
189b67d407aSToomas Soome 			} else if (subtopic == NULL && s != NULL) {
190ca987d46SWarner Losh 				/* topic match, list subtopics */
191ca987d46SWarner Losh 				if (help_emitsummary(t, s, d))
192ca987d46SWarner Losh 					break;
193ca987d46SWarner Losh 			}
194ca987d46SWarner Losh 		}
195ca987d46SWarner Losh 		free(t);
196ca987d46SWarner Losh 		free(s);
197ca987d46SWarner Losh 		free(d);
19874ecc441SWarner Losh 		t = s = d = NULL;
199ca987d46SWarner Losh 	}
20074ecc441SWarner Losh 	free(t);
20174ecc441SWarner Losh 	free(s);
20274ecc441SWarner Losh 	free(d);
203ca987d46SWarner Losh 	pager_close();
204ca987d46SWarner Losh 	close(hfd);
205ca987d46SWarner Losh 	if (!matched) {
206ca987d46SWarner Losh 		snprintf(command_errbuf, sizeof(command_errbuf),
207ca987d46SWarner Losh 		    "no help available for '%s'", topic);
208ca987d46SWarner Losh 		free(topic);
209ca987d46SWarner Losh 		free(subtopic);
210ca987d46SWarner Losh 		return (CMD_ERROR);
211ca987d46SWarner Losh 	}
212ca987d46SWarner Losh 	free(topic);
213ca987d46SWarner Losh 	free(subtopic);
214ca987d46SWarner Losh 	return (CMD_OK);
215ca987d46SWarner Losh }
216ca987d46SWarner Losh 
217ca987d46SWarner Losh COMMAND_SET(commandlist, "?", "list commands", command_commandlist);
218ca987d46SWarner Losh 
219ca987d46SWarner Losh /*
220ca987d46SWarner Losh  * Please note: although we use the pager for the list of commands,
221ca987d46SWarner Losh  * this routine is called from the ? FORTH function which then
222ca987d46SWarner Losh  * unconditionally prints some commands. This will lead to anomalous
223ca987d46SWarner Losh  * behavior. There's no 'pager_output' binding to FORTH to allow
224ca987d46SWarner Losh  * things to work right, so I'm documenting the bug rather than
225ca987d46SWarner Losh  * fixing it.
226ca987d46SWarner Losh  */
227ca987d46SWarner Losh static int
command_commandlist(int argc __unused,char * argv[]__unused)228b67d407aSToomas Soome command_commandlist(int argc __unused, char *argv[] __unused)
229ca987d46SWarner Losh {
230ca987d46SWarner Losh 	struct bootblk_command	**cmdp;
231ca987d46SWarner Losh 	int	res;
232*ab08da53SAhmad Khalifa 	char	name[23];
233ca987d46SWarner Losh 
234ca987d46SWarner Losh 	res = 0;
235ca987d46SWarner Losh 	pager_open();
236ca987d46SWarner Losh 	res = pager_output("Available commands:\n");
237ca987d46SWarner Losh 	SET_FOREACH(cmdp, Xcommand_set) {
238ca987d46SWarner Losh 		if (res)
239ca987d46SWarner Losh 			break;
240b67d407aSToomas Soome 		if ((*cmdp)->c_name != NULL && (*cmdp)->c_desc != NULL) {
241*ab08da53SAhmad Khalifa 			snprintf(name, sizeof(name), "  %-20s",
242b67d407aSToomas Soome 			    (*cmdp)->c_name);
243ca987d46SWarner Losh 			pager_output(name);
244*ab08da53SAhmad Khalifa 			pager_output("  ");
245ca987d46SWarner Losh 			pager_output((*cmdp)->c_desc);
246ca987d46SWarner Losh 			res = pager_output("\n");
247ca987d46SWarner Losh 		}
248ca987d46SWarner Losh 	}
249ca987d46SWarner Losh 	pager_close();
250ca987d46SWarner Losh 	return (CMD_OK);
251ca987d46SWarner Losh }
252ca987d46SWarner Losh 
253ca987d46SWarner Losh /*
254ca987d46SWarner Losh  * XXX set/show should become set/echo if we have variable
255ca987d46SWarner Losh  * substitution happening.
256ca987d46SWarner Losh  */
257ca987d46SWarner Losh 
258ca987d46SWarner Losh COMMAND_SET(show, "show", "show variable(s)", command_show);
259ca987d46SWarner Losh 
260ca987d46SWarner Losh static int
command_show(int argc,char * argv[])261ca987d46SWarner Losh command_show(int argc, char *argv[])
262ca987d46SWarner Losh {
263ca987d46SWarner Losh 	struct env_var	*ev;
264ca987d46SWarner Losh 	char		*cp;
265ca987d46SWarner Losh 
266ca987d46SWarner Losh 	if (argc < 2) {
267ca987d46SWarner Losh 		/*
268ca987d46SWarner Losh 		 * With no arguments, print everything.
269ca987d46SWarner Losh 		 */
270ca987d46SWarner Losh 		pager_open();
271ca987d46SWarner Losh 		for (ev = environ; ev != NULL; ev = ev->ev_next) {
272ca987d46SWarner Losh 			pager_output(ev->ev_name);
273ca987d46SWarner Losh 			cp = getenv(ev->ev_name);
274ca987d46SWarner Losh 			if (cp != NULL) {
275ca987d46SWarner Losh 				pager_output("=");
276ca987d46SWarner Losh 				pager_output(cp);
277ca987d46SWarner Losh 			}
278ca987d46SWarner Losh 			if (pager_output("\n"))
279ca987d46SWarner Losh 				break;
280ca987d46SWarner Losh 		}
281ca987d46SWarner Losh 		pager_close();
282ca987d46SWarner Losh 	} else {
283ca987d46SWarner Losh 		if ((cp = getenv(argv[1])) != NULL) {
284ca987d46SWarner Losh 			printf("%s\n", cp);
285ca987d46SWarner Losh 		} else {
286ca987d46SWarner Losh 			snprintf(command_errbuf, sizeof(command_errbuf),
287ca987d46SWarner Losh 			    "variable '%s' not found", argv[1]);
288ca987d46SWarner Losh 			return (CMD_ERROR);
289ca987d46SWarner Losh 		}
290ca987d46SWarner Losh 	}
291ca987d46SWarner Losh 	return (CMD_OK);
292ca987d46SWarner Losh }
293ca987d46SWarner Losh 
294ca987d46SWarner Losh COMMAND_SET(set, "set", "set a variable", command_set);
295ca987d46SWarner Losh 
296ca987d46SWarner Losh static int
command_set(int argc,char * argv[])297ca987d46SWarner Losh command_set(int argc, char *argv[])
298ca987d46SWarner Losh {
299ca987d46SWarner Losh 	int	err;
300ca987d46SWarner Losh 
301ca987d46SWarner Losh 	if (argc != 2) {
302ca987d46SWarner Losh 		command_errmsg = "wrong number of arguments";
303ca987d46SWarner Losh 		return (CMD_ERROR);
304ca987d46SWarner Losh 	} else {
305bbac74caSSimon J. Gerraty #ifdef LOADER_VERIEXEC
306bbac74caSSimon J. Gerraty 		/*
307bbac74caSSimon J. Gerraty 		 * Impose restrictions if input is not verified
308bbac74caSSimon J. Gerraty 		 */
309bbac74caSSimon J. Gerraty 		const char *restricted[] = {
310bbac74caSSimon J. Gerraty 			"boot",
311bbac74caSSimon J. Gerraty 			"init",
312bbac74caSSimon J. Gerraty 			"loader.ve.",
313bbac74caSSimon J. Gerraty 			"rootfs",
314bbac74caSSimon J. Gerraty 			"secur",
315bbac74caSSimon J. Gerraty 			"vfs.",
316bbac74caSSimon J. Gerraty 			NULL,
317bbac74caSSimon J. Gerraty 		};
318bbac74caSSimon J. Gerraty 		const char **cp;
319bbac74caSSimon J. Gerraty 		int ves;
320bbac74caSSimon J. Gerraty 
321bbac74caSSimon J. Gerraty 		ves = ve_status_get(-1);
322bbac74caSSimon J. Gerraty 		if (ves == VE_UNVERIFIED_OK) {
323bbac74caSSimon J. Gerraty #ifdef LOADER_VERIEXEC_TESTING
324bbac74caSSimon J. Gerraty 			printf("Checking: %s\n", argv[1]);
325bbac74caSSimon J. Gerraty #endif
326bbac74caSSimon J. Gerraty 			for (cp = restricted; *cp; cp++) {
327bbac74caSSimon J. Gerraty 				if (strncmp(argv[1], *cp, strlen(*cp)) == 0) {
328bbac74caSSimon J. Gerraty 					printf("Ignoring restricted variable: %s\n",
329bbac74caSSimon J. Gerraty 					    argv[1]);
330bbac74caSSimon J. Gerraty 					return (CMD_OK);
331bbac74caSSimon J. Gerraty 				}
332bbac74caSSimon J. Gerraty 			}
333bbac74caSSimon J. Gerraty 		}
334bbac74caSSimon J. Gerraty #endif
335ca987d46SWarner Losh 		if ((err = putenv(argv[1])) != 0) {
336ca987d46SWarner Losh 			command_errmsg = strerror(err);
337ca987d46SWarner Losh 			return (CMD_ERROR);
338ca987d46SWarner Losh 		}
339ca987d46SWarner Losh 	}
340ca987d46SWarner Losh 	return (CMD_OK);
341ca987d46SWarner Losh }
342ca987d46SWarner Losh 
343ca987d46SWarner Losh COMMAND_SET(unset, "unset", "unset a variable", command_unset);
344ca987d46SWarner Losh 
345ca987d46SWarner Losh static int
command_unset(int argc,char * argv[])346ca987d46SWarner Losh command_unset(int argc, char *argv[])
347ca987d46SWarner Losh {
348ca987d46SWarner Losh 	int	err;
349ca987d46SWarner Losh 
350ca987d46SWarner Losh 	if (argc != 2) {
351ca987d46SWarner Losh 		command_errmsg = "wrong number of arguments";
352ca987d46SWarner Losh 		return (CMD_ERROR);
353ca987d46SWarner Losh 	} else {
354ca987d46SWarner Losh 		if ((err = unsetenv(argv[1])) != 0) {
355ca987d46SWarner Losh 			command_errmsg = strerror(err);
356ca987d46SWarner Losh 			return (CMD_ERROR);
357ca987d46SWarner Losh 		}
358ca987d46SWarner Losh 	}
359ca987d46SWarner Losh 	return (CMD_OK);
360ca987d46SWarner Losh }
361ca987d46SWarner Losh 
362ca987d46SWarner Losh COMMAND_SET(echo, "echo", "echo arguments", command_echo);
363ca987d46SWarner Losh 
364ca987d46SWarner Losh static int
command_echo(int argc,char * argv[])365ca987d46SWarner Losh command_echo(int argc, char *argv[])
366ca987d46SWarner Losh {
367ca987d46SWarner Losh 	char	*s;
368ca987d46SWarner Losh 	int	nl, ch;
369ca987d46SWarner Losh 
370ca987d46SWarner Losh 	nl = 0;
371ca987d46SWarner Losh 	optind = 1;
372ca987d46SWarner Losh 	optreset = 1;
373ca987d46SWarner Losh 	while ((ch = getopt(argc, argv, "n")) != -1) {
374ca987d46SWarner Losh 		switch (ch) {
375ca987d46SWarner Losh 		case 'n':
376ca987d46SWarner Losh 			nl = 1;
377ca987d46SWarner Losh 			break;
378ca987d46SWarner Losh 		case '?':
379ca987d46SWarner Losh 		default:
380ca987d46SWarner Losh 			/* getopt has already reported an error */
381ca987d46SWarner Losh 			return (CMD_OK);
382ca987d46SWarner Losh 		}
383ca987d46SWarner Losh 	}
384ca987d46SWarner Losh 	argv += (optind);
385ca987d46SWarner Losh 	argc -= (optind);
386ca987d46SWarner Losh 
387ca987d46SWarner Losh 	s = unargv(argc, argv);
388ca987d46SWarner Losh 	if (s != NULL) {
389ca987d46SWarner Losh 		printf("%s", s);
390ca987d46SWarner Losh 		free(s);
391ca987d46SWarner Losh 	}
392ca987d46SWarner Losh 	if (!nl)
393ca987d46SWarner Losh 		printf("\n");
394ca987d46SWarner Losh 	return (CMD_OK);
395ca987d46SWarner Losh }
396ca987d46SWarner Losh 
397ca987d46SWarner Losh /*
398ca987d46SWarner Losh  * A passable emulation of the sh(1) command of the same name.
399ca987d46SWarner Losh  */
400ca987d46SWarner Losh 
401ca987d46SWarner Losh COMMAND_SET(read, "read", "read input from the terminal", command_read);
402ca987d46SWarner Losh 
403ca987d46SWarner Losh static int
command_read(int argc,char * argv[])404ca987d46SWarner Losh command_read(int argc, char *argv[])
405ca987d46SWarner Losh {
406ca987d46SWarner Losh 	char	*prompt;
407ca987d46SWarner Losh 	int	timeout;
408ca987d46SWarner Losh 	time_t	when;
409ca987d46SWarner Losh 	char	*cp;
410ca987d46SWarner Losh 	char	*name;
411ca987d46SWarner Losh 	char	buf[256];		/* XXX size? */
412ca987d46SWarner Losh 	int	c;
413ca987d46SWarner Losh 
414ca987d46SWarner Losh 	timeout = -1;
415ca987d46SWarner Losh 	prompt = NULL;
416ca987d46SWarner Losh 	optind = 1;
417ca987d46SWarner Losh 	optreset = 1;
418ca987d46SWarner Losh 	while ((c = getopt(argc, argv, "p:t:")) != -1) {
419ca987d46SWarner Losh 		switch (c) {
420ca987d46SWarner Losh 		case 'p':
421ca987d46SWarner Losh 			prompt = optarg;
422ca987d46SWarner Losh 			break;
423ca987d46SWarner Losh 		case 't':
424ca987d46SWarner Losh 			timeout = strtol(optarg, &cp, 0);
425ca987d46SWarner Losh 			if (cp == optarg) {
426b67d407aSToomas Soome 				snprintf(command_errbuf,
427b67d407aSToomas Soome 				    sizeof(command_errbuf),
428ca987d46SWarner Losh 				    "bad timeout '%s'", optarg);
429ca987d46SWarner Losh 				return (CMD_ERROR);
430ca987d46SWarner Losh 			}
431ca987d46SWarner Losh 			break;
432ca987d46SWarner Losh 		default:
433ca987d46SWarner Losh 			return (CMD_OK);
434ca987d46SWarner Losh 		}
435ca987d46SWarner Losh 	}
436ca987d46SWarner Losh 
437ca987d46SWarner Losh 	argv += (optind);
438ca987d46SWarner Losh 	argc -= (optind);
439ca987d46SWarner Losh 	name = (argc > 0) ? argv[0]: NULL;
440ca987d46SWarner Losh 
441ca987d46SWarner Losh 	if (prompt != NULL)
442ca987d46SWarner Losh 		printf("%s", prompt);
443ca987d46SWarner Losh 	if (timeout >= 0) {
444ca987d46SWarner Losh 		when = time(NULL) + timeout;
445ca987d46SWarner Losh 		while (!ischar())
446ca987d46SWarner Losh 			if (time(NULL) >= when)
447ca987d46SWarner Losh 				return (CMD_OK); /* is timeout an error? */
448ca987d46SWarner Losh 	}
449ca987d46SWarner Losh 
450ca987d46SWarner Losh 	ngets(buf, sizeof(buf));
451ca987d46SWarner Losh 
452ca987d46SWarner Losh 	if (name != NULL)
453ca987d46SWarner Losh 		setenv(name, buf, 1);
454ca987d46SWarner Losh 	return (CMD_OK);
455ca987d46SWarner Losh }
456ca987d46SWarner Losh 
457ca987d46SWarner Losh /*
458ca987d46SWarner Losh  * File pager
459ca987d46SWarner Losh  */
460ca987d46SWarner Losh COMMAND_SET(more, "more", "show contents of a file", command_more);
461ca987d46SWarner Losh 
462ca987d46SWarner Losh static int
command_more(int argc,char * argv[])463ca987d46SWarner Losh command_more(int argc, char *argv[])
464ca987d46SWarner Losh {
465ca987d46SWarner Losh 	int	i;
466ca987d46SWarner Losh 	int	res;
467ca987d46SWarner Losh 	char	line[80];
468ca987d46SWarner Losh 
469ca987d46SWarner Losh 	res = 0;
470ca987d46SWarner Losh 	pager_open();
471ca987d46SWarner Losh 	for (i = 1; (i < argc) && (res == 0); i++) {
472b67d407aSToomas Soome 		snprintf(line, sizeof(line), "*** FILE %s BEGIN ***\n",
473b67d407aSToomas Soome 		    argv[i]);
474ca987d46SWarner Losh 		if (pager_output(line))
475ca987d46SWarner Losh 			break;
476ca987d46SWarner Losh 		res = page_file(argv[i]);
477ca987d46SWarner Losh 		if (!res) {
478b67d407aSToomas Soome 			snprintf(line, sizeof(line), "*** FILE %s END ***\n",
479b67d407aSToomas Soome 			    argv[i]);
480ca987d46SWarner Losh 			res = pager_output(line);
481ca987d46SWarner Losh 		}
482ca987d46SWarner Losh 	}
483ca987d46SWarner Losh 	pager_close();
484ca987d46SWarner Losh 
485b67d407aSToomas Soome 	return (CMD_OK);
486ca987d46SWarner Losh }
487ca987d46SWarner Losh 
488ca987d46SWarner Losh static int
page_file(char * filename)489ca987d46SWarner Losh page_file(char *filename)
490ca987d46SWarner Losh {
491ca987d46SWarner Losh 	int result;
492ca987d46SWarner Losh 
493ca987d46SWarner Losh 	result = pager_file(filename);
494ca987d46SWarner Losh 
495ca987d46SWarner Losh 	if (result == -1) {
496ca987d46SWarner Losh 		snprintf(command_errbuf, sizeof(command_errbuf),
497ca987d46SWarner Losh 		    "error showing %s", filename);
498ca987d46SWarner Losh 	}
499ca987d46SWarner Losh 
500b67d407aSToomas Soome 	return (result);
501ca987d46SWarner Losh }
502ca987d46SWarner Losh 
503ca987d46SWarner Losh /*
504ca987d46SWarner Losh  * List all disk-like devices
505ca987d46SWarner Losh  */
506ca987d46SWarner Losh COMMAND_SET(lsdev, "lsdev", "list all devices", command_lsdev);
507ca987d46SWarner Losh 
508ca987d46SWarner Losh static int
command_lsdev(int argc,char * argv[])509ca987d46SWarner Losh command_lsdev(int argc, char *argv[])
510ca987d46SWarner Losh {
511ca987d46SWarner Losh 	int	verbose, ch, i;
512ca987d46SWarner Losh 	char	line[80];
513ca987d46SWarner Losh 
514ca987d46SWarner Losh 	verbose = 0;
515ca987d46SWarner Losh 	optind = 1;
516ca987d46SWarner Losh 	optreset = 1;
517ca987d46SWarner Losh 	while ((ch = getopt(argc, argv, "v")) != -1) {
518ca987d46SWarner Losh 		switch (ch) {
519ca987d46SWarner Losh 		case 'v':
520ca987d46SWarner Losh 			verbose = 1;
521ca987d46SWarner Losh 			break;
522ca987d46SWarner Losh 		case '?':
523ca987d46SWarner Losh 		default:
524ca987d46SWarner Losh 			/* getopt has already reported an error */
525ca987d46SWarner Losh 			return (CMD_OK);
526ca987d46SWarner Losh 		}
527ca987d46SWarner Losh 	}
528ca987d46SWarner Losh 	argv += (optind);
529ca987d46SWarner Losh 	argc -= (optind);
530ca987d46SWarner Losh 
531ca987d46SWarner Losh 	pager_open();
532ca987d46SWarner Losh 	for (i = 0; devsw[i] != NULL; i++) {
533ca987d46SWarner Losh 		if (devsw[i]->dv_print != NULL) {
534ca987d46SWarner Losh 			if (devsw[i]->dv_print(verbose))
535ca987d46SWarner Losh 				break;
536ca987d46SWarner Losh 		} else {
537b67d407aSToomas Soome 			snprintf(line, sizeof(line), "%s: (unknown)\n",
538b67d407aSToomas Soome 			    devsw[i]->dv_name);
539ca987d46SWarner Losh 			if (pager_output(line))
540ca987d46SWarner Losh 				break;
541ca987d46SWarner Losh 		}
542ca987d46SWarner Losh 	}
543ca987d46SWarner Losh 	pager_close();
544ca987d46SWarner Losh 	return (CMD_OK);
545ca987d46SWarner Losh }
54670661eaaSEmmanuel Vadot 
54770661eaaSEmmanuel Vadot static int
command_readtest(int argc,char * argv[])54870661eaaSEmmanuel Vadot command_readtest(int argc, char *argv[])
54970661eaaSEmmanuel Vadot {
55070661eaaSEmmanuel Vadot 	int fd;
55170661eaaSEmmanuel Vadot 	time_t start, end;
55270661eaaSEmmanuel Vadot 	char buf[512];
55370661eaaSEmmanuel Vadot 	ssize_t rv, count = 0;
55470661eaaSEmmanuel Vadot 
55570661eaaSEmmanuel Vadot 	if (argc != 2) {
55670661eaaSEmmanuel Vadot 		snprintf(command_errbuf, sizeof(command_errbuf),
55770661eaaSEmmanuel Vadot 		  "Usage: readtest <filename>");
55870661eaaSEmmanuel Vadot 		return (CMD_ERROR);
55970661eaaSEmmanuel Vadot 	}
56070661eaaSEmmanuel Vadot 
56170661eaaSEmmanuel Vadot 	start = getsecs();
56270661eaaSEmmanuel Vadot 	if ((fd = open(argv[1], O_RDONLY)) < 0) {
56370661eaaSEmmanuel Vadot 		snprintf(command_errbuf, sizeof(command_errbuf),
56470661eaaSEmmanuel Vadot 		  "can't open '%s'", argv[1]);
56570661eaaSEmmanuel Vadot 		return (CMD_ERROR);
56670661eaaSEmmanuel Vadot 	}
56770661eaaSEmmanuel Vadot 	while ((rv = read(fd, buf, sizeof(buf))) > 0)
56870661eaaSEmmanuel Vadot 		count += rv;
56970661eaaSEmmanuel Vadot 	end = getsecs();
57070661eaaSEmmanuel Vadot 
57170661eaaSEmmanuel Vadot 	printf("Received %zd bytes during %jd seconds\n", count, (intmax_t)end - start);
57270661eaaSEmmanuel Vadot 	close(fd);
57370661eaaSEmmanuel Vadot 	return (CMD_OK);
57470661eaaSEmmanuel Vadot }
57570661eaaSEmmanuel Vadot 
57670661eaaSEmmanuel Vadot COMMAND_SET(readtest, "readtest", "Time a file read", command_readtest);
5772101541fSWarner Losh 
5782101541fSWarner Losh static int
command_quit(int argc,char * argv[])5792101541fSWarner Losh command_quit(int argc, char *argv[])
5802101541fSWarner Losh {
5812101541fSWarner Losh 	exit(0);
5822101541fSWarner Losh 	return (CMD_OK);
5832101541fSWarner Losh }
5842101541fSWarner Losh 
5852101541fSWarner Losh COMMAND_SET(quit, "quit", "exit the loader", command_quit);
586