xref: /openbsd-src/sys/stand/boot/cmd.c (revision a4f11372d5ec16405c3947a49e9200b89358d82d)
1*a4f11372Smiod /*	$OpenBSD: cmd.c,v 1.70 2023/02/23 19:48:22 miod Exp $	*/
2df1f5d3aSweingart 
3df1f5d3aSweingart /*
4dcabde39Smickey  * Copyright (c) 1997-1999 Michael Shalayeff
5df1f5d3aSweingart  * All rights reserved.
6df1f5d3aSweingart  *
7df1f5d3aSweingart  * Redistribution and use in source and binary forms, with or without
8df1f5d3aSweingart  * modification, are permitted provided that the following conditions
9df1f5d3aSweingart  * are met:
10df1f5d3aSweingart  * 1. Redistributions of source code must retain the above copyright
11df1f5d3aSweingart  *    notice, this list of conditions and the following disclaimer.
12df1f5d3aSweingart  * 2. Redistributions in binary form must reproduce the above copyright
13df1f5d3aSweingart  *    notice, this list of conditions and the following disclaimer in the
14df1f5d3aSweingart  *    documentation and/or other materials provided with the distribution.
15df1f5d3aSweingart  *
16df1f5d3aSweingart  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17df1f5d3aSweingart  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18df1f5d3aSweingart  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19df1f5d3aSweingart  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20df1f5d3aSweingart  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21df1f5d3aSweingart  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22df1f5d3aSweingart  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23df1f5d3aSweingart  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24df1f5d3aSweingart  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25df1f5d3aSweingart  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26df1f5d3aSweingart  * SUCH DAMAGE.
27df1f5d3aSweingart  */
28df1f5d3aSweingart 
29df1f5d3aSweingart #include <sys/param.h>
30101ff5ddSderaadt #include <sys/reboot.h>
318113530bStom 
328113530bStom #include <libsa.h>
331ee9984cSderaadt #include <lib/libkern/funcs.h>
348113530bStom 
35df1f5d3aSweingart #include "cmd.h"
36df1f5d3aSweingart 
3750811cfaSmickey #define CTRL(c)	((c)&0x1f)
3850811cfaSmickey 
39c4071fd1Smillert static int Xboot(void);
40c4071fd1Smillert static int Xecho(void);
41c4071fd1Smillert static int Xhelp(void);
423fbdbb31Sbluhm static int Xhexdump(void);
43c4071fd1Smillert static int Xls(void);
44c4071fd1Smillert static int Xnop(void);
45c4071fd1Smillert static int Xreboot(void);
46*a4f11372Smiod #ifdef BOOT_STTY
47c4071fd1Smillert static int Xstty(void);
48*a4f11372Smiod #endif
49c4071fd1Smillert static int Xtime(void);
50cd073bdfSmickey #ifdef MACHINE_CMD
51c4071fd1Smillert static int Xmachine(void);
52cd073bdfSmickey extern const struct cmd_table MACHINE_CMD[];
53cd073bdfSmickey #endif
54c4071fd1Smillert extern int Xset(void);
55c4071fd1Smillert extern int Xenv(void);
56dc461ba4Smickey 
577f20cbb1Stom #ifdef CHECK_SKIP_CONF
587f20cbb1Stom extern int CHECK_SKIP_CONF(void);
597f20cbb1Stom #endif
607f20cbb1Stom 
614686fe07Smickey extern const struct cmd_table cmd_set[];
629f2d58dfSderaadt const struct cmd_table cmd_table[] = {
631ee788beSweingart 	{"#",      CMDT_CMD, Xnop},  /* XXX must be first */
641ee788beSweingart 	{"boot",   CMDT_CMD, Xboot},
6595e5d945Smickey 	{"echo",   CMDT_CMD, Xecho},
664686fe07Smickey 	{"env",    CMDT_CMD, Xenv},
6795e5d945Smickey 	{"help",   CMDT_CMD, Xhelp},
683fbdbb31Sbluhm 	{"hexdump",CMDT_CMD, Xhexdump},
6995e5d945Smickey 	{"ls",     CMDT_CMD, Xls},
70cd073bdfSmickey #ifdef MACHINE_CMD
71cd073bdfSmickey 	{"machine",CMDT_MDC, Xmachine},
72cd073bdfSmickey #endif
7395e5d945Smickey 	{"reboot", CMDT_CMD, Xreboot},
7495e5d945Smickey 	{"set",    CMDT_SET, Xset},
75*a4f11372Smiod #ifdef BOOT_STTY
76e20327dbSflipk 	{"stty",   CMDT_CMD, Xstty},
77*a4f11372Smiod #endif
7895e5d945Smickey 	{"time",   CMDT_CMD, Xtime},
79df1f5d3aSweingart 	{NULL, 0},
80df1f5d3aSweingart };
81df1f5d3aSweingart 
82599546b3Sderaadt static void ls(char *, struct stat *);
83599546b3Sderaadt static int readline(char *, size_t, int);
84599546b3Sderaadt char *nextword(char *);
85599546b3Sderaadt static char *whatcmd(const struct cmd_table **ct, char *);
86c4071fd1Smillert static char *qualify(char *);
871ad1f950Smickey 
888113530bStom char cmd_buf[CMD_BUFF_SIZE];
89df1f5d3aSweingart 
90df1f5d3aSweingart int
getcmd(void)91599546b3Sderaadt getcmd(void)
921ad1f950Smickey {
935c487e4aSmickey 	cmd.cmd = NULL;
941ad1f950Smickey 
95a8480c01Smickey 	if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout))
965c487e4aSmickey 		cmd.cmd = cmd_table;
971ad1f950Smickey 
985c487e4aSmickey 	return docmd();
991ad1f950Smickey }
1001ad1f950Smickey 
1011ad1f950Smickey int
read_conf(void)102599546b3Sderaadt read_conf(void)
1031ad1f950Smickey {
1041ad1f950Smickey #ifndef INSECURE
1051ad1f950Smickey 	struct stat sb;
1061ad1f950Smickey #endif
10728f0434cStom 	int fd, rc = 0;
1081ad1f950Smickey 
1097f20cbb1Stom #ifdef CHECK_SKIP_CONF
1107f20cbb1Stom 	if (CHECK_SKIP_CONF()) {
1117f20cbb1Stom 		printf("boot.conf processing skipped at operator request\n");
1129a2c2bcaSsthen 		cmd.timeout = 0;
1137f20cbb1Stom 		return -1;		/* Pretend file wasn't found */
1147f20cbb1Stom 	}
1157f20cbb1Stom #endif
1167f20cbb1Stom 
117d6da11dcSderaadt 	if ((fd = open(qualify(cmd.conf), O_RDONLY)) < 0) {
118d199f0b3Smickey 		if (errno != ENOENT && errno != ENXIO) {
1195c487e4aSmickey 			printf("open(%s): %s\n", cmd.path, strerror(errno));
1201ad1f950Smickey 			return 0;
1211ad1f950Smickey 		}
1221ad1f950Smickey 		return -1;
1231ad1f950Smickey 	}
1241ad1f950Smickey 
1251ad1f950Smickey #ifndef INSECURE
1261ad1f950Smickey 	(void) fstat(fd, &sb);
1271ad1f950Smickey 	if (sb.st_uid || (sb.st_mode & 2)) {
1285c487e4aSmickey 		printf("non-secure %s, will not proceed\n", cmd.path);
1291ad1f950Smickey 		close(fd);
1301ad1f950Smickey 		return -1;
1311ad1f950Smickey 	}
1321ad1f950Smickey #endif
1331ad1f950Smickey 
1341ad1f950Smickey 	do {
135599546b3Sderaadt 		char *p = cmd_buf;
1361ad1f950Smickey 
1375c487e4aSmickey 		cmd.cmd = NULL;
1381ee9984cSderaadt 		do {
13928f0434cStom 			rc = read(fd, p, 1);
14028f0434cStom 		} while (rc > 0 && *p++ != '\n' &&
14128f0434cStom 		    (p-cmd_buf) < sizeof(cmd_buf));
1421ad1f950Smickey 
14309cfa7dcStom 		if (rc < 0) {			/* Error from read() */
1445c487e4aSmickey 			printf("%s: %s\n", cmd.path, strerror(errno));
14509cfa7dcStom 			break;
14609cfa7dcStom 		}
14709cfa7dcStom 
14809cfa7dcStom 		if (rc == 0) {			/* eof from read() */
14909cfa7dcStom 			if (p != cmd_buf) {	/* Line w/o trailing \n */
15009cfa7dcStom 				*p = '\0';
15109cfa7dcStom 				rc = docmd();
15209cfa7dcStom 				break;
15309cfa7dcStom 			}
15409cfa7dcStom 		} else {			/* rc > 0, read a char */
15528f0434cStom 			p--;			/* Get back to last character */
1561ad1f950Smickey 
15728f0434cStom 			if (*p != '\n') {	/* Line was too long */
15828f0434cStom 				printf("%s: line too long\n", cmd.path);
15928f0434cStom 
16028f0434cStom 				/* Don't want to run the truncated command */
16128f0434cStom 				rc = -1;
16228f0434cStom 			}
16328f0434cStom 			*p = '\0';
16428f0434cStom 		}
16528f0434cStom 	} while (rc > 0 && !(rc = docmd()));
1661ad1f950Smickey 
1671ad1f950Smickey 	close(fd);
16828f0434cStom 	return rc;
1691ad1f950Smickey }
1701ad1f950Smickey 
1718113530bStom int
docmd(void)172599546b3Sderaadt docmd(void)
173df1f5d3aSweingart {
174599546b3Sderaadt 	char *p = NULL;
1751ee788beSweingart 	const struct cmd_table *ct = cmd_table, *cs;
1761e251da8Smickey 
1775c487e4aSmickey 	cmd.argc = 1;
1785c487e4aSmickey 	if (cmd.cmd == NULL) {
179df1f5d3aSweingart 
1801e251da8Smickey 		/* command */
18155a4a89cStom 		for (p = cmd_buf; *p == ' ' || *p == '\t'; p++)
182101ff5ddSderaadt 			;
1831ad1f950Smickey 		if (*p == '#' || *p == '\0') { /* comment or empty string */
1841ad1f950Smickey #ifdef DEBUG
1851ad1f950Smickey 			printf("rem\n");
1861ad1f950Smickey #endif
1871ad1f950Smickey 			return 0;
1881ad1f950Smickey 		}
189dc461ba4Smickey 		ct = cmd_table;
190cd073bdfSmickey 		cs = NULL;
1915c487e4aSmickey 		cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */
192dc461ba4Smickey 		p = whatcmd(&ct, p);
193dc461ba4Smickey 		if (ct == NULL) {
1945c487e4aSmickey 			cmd.argc++;
195dc461ba4Smickey 			ct = cmd_table;
19695e5d945Smickey 		} else if (ct->cmd_type == CMDT_SET && p != NULL) {
197cd073bdfSmickey 			cs = cmd_set;
198cd073bdfSmickey #ifdef MACHINE_CMD
199cd073bdfSmickey 		} else if (ct->cmd_type == CMDT_MDC && p != NULL) {
200cd073bdfSmickey 			cs = MACHINE_CMD;
201cd073bdfSmickey #endif
202cd073bdfSmickey 		}
203cd073bdfSmickey 
204cd073bdfSmickey 		if (cs != NULL) {
205dc461ba4Smickey 			p = whatcmd(&cs, p);
206dc461ba4Smickey 			if (cs == NULL) {
207dc461ba4Smickey 				printf("%s: syntax error\n", ct->cmd_name);
208dc461ba4Smickey 				return 0;
209283d4f9cSderaadt 			}
210dc461ba4Smickey 			ct = cs;
211dc461ba4Smickey 		}
2125c487e4aSmickey 		cmd.cmd = ct;
213dc461ba4Smickey 	}
214dc461ba4Smickey 
2155c487e4aSmickey 	cmd.argv[0] = ct->cmd_name;
2165c487e4aSmickey 	while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) {
2175c487e4aSmickey 		cmd.argv[cmd.argc++] = p;
218101ff5ddSderaadt 		p = nextword(p);
219df1f5d3aSweingart 	}
2205c487e4aSmickey 	cmd.argv[cmd.argc] = NULL;
221dc461ba4Smickey 
2225c487e4aSmickey 	return (*cmd.cmd->cmd_exec)();
223dc461ba4Smickey }
224dc461ba4Smickey 
225dc461ba4Smickey static char *
whatcmd(const struct cmd_table ** ct,char * p)226599546b3Sderaadt whatcmd(const struct cmd_table **ct, char *p)
227dc461ba4Smickey {
228599546b3Sderaadt 	char *q;
229599546b3Sderaadt 	int l;
230dc461ba4Smickey 
231dc461ba4Smickey 	q = nextword(p);
232dc461ba4Smickey 
233dc461ba4Smickey 	for (l = 0; p[l]; l++)
234dc461ba4Smickey 		;
235dc461ba4Smickey 
236dc461ba4Smickey 	while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l))
237dc461ba4Smickey 		(*ct)++;
238dc461ba4Smickey 
239dc461ba4Smickey 	if ((*ct)->cmd_name == NULL)
240dc461ba4Smickey 		*ct = NULL;
241dc461ba4Smickey 
242dc461ba4Smickey 	return q;
243df1f5d3aSweingart }
244df1f5d3aSweingart 
2451e251da8Smickey static int
readline(char * buf,size_t n,int to)246599546b3Sderaadt readline(char *buf, size_t n, int to)
247df1f5d3aSweingart {
2483ed0b71cSmickey #ifdef DEBUG
2493ed0b71cSmickey 	extern int debug;
2503ed0b71cSmickey #endif
251599546b3Sderaadt 	char *p = buf, ch;
252df1f5d3aSweingart 
2531ee788beSweingart 	/* Only do timeout if greater than 0 */
2541ee788beSweingart 	if (to > 0) {
255dcabde39Smickey 		time_t tt = getsecs() + to;
25608149514Smickey #ifdef DEBUG
25708149514Smickey 		if (debug > 2)
2583ed0b71cSmickey 			printf ("readline: timeout(%d) at %u\n", to, tt);
25908149514Smickey #endif
260b83d90f0Smiod 		while (!cnischar() && getsecs() < tt)
261b83d90f0Smiod 			continue;
2620bbb8e25Smickey 
2631ee788beSweingart 		if (!cnischar()) {
2641ee9984cSderaadt 			strlcpy(buf, "boot", 5);
26530f9d02dSmickey 			putchar('\n');
2661ee788beSweingart 			return strlen(buf);
2671ee788beSweingart 		}
2681ee788beSweingart 	} else
2691ee9984cSderaadt 		while (!cnischar())
2701ee9984cSderaadt 			;
2711e251da8Smickey 
272baf03119Stom 	/* User has typed something.  Turn off timeouts. */
273baf03119Stom 	cmd.timeout = 0;
274baf03119Stom 
2751e251da8Smickey 	while (1) {
276101ff5ddSderaadt 		switch ((ch = getchar())) {
27750811cfaSmickey 		case CTRL('u'):
2781d32fee5Smdw 			while (p > buf) {
279bd53aa64Smickey 				putchar('\177');
2801d32fee5Smdw 				p--;
2811d32fee5Smdw 			}
28250811cfaSmickey 			continue;
2831e251da8Smickey 		case '\n':
284c657d8f4Sniklas 		case '\r':
2852d99e3c1Stobias 			*p = '\0';
2861e251da8Smickey 			break;
2871e251da8Smickey 		case '\b':
288c657d8f4Sniklas 		case '\177':
2891e251da8Smickey 			if (p > buf) {
29070276cf0Skstailey 				putchar('\177');
2911e251da8Smickey 				p--;
2921e251da8Smickey 			}
2931e251da8Smickey 			continue;
2941e251da8Smickey 		default:
29595a60db5Sderaadt 			if (ch >= ' ' && ch < '\177') {
296a8480c01Smickey 				if (p - buf < n-1)
2971e251da8Smickey 					*p++ = ch;
298a8480c01Smickey 				else {
299a8480c01Smickey 					putchar('\007');
300a8480c01Smickey 					putchar('\177');
301a8480c01Smickey 				}
30295a60db5Sderaadt 			}
3031e251da8Smickey 			continue;
3041e251da8Smickey 		}
3051e251da8Smickey 		break;
3061e251da8Smickey 	}
30750811cfaSmickey 
308a8480c01Smickey 	return p - buf;
3091e251da8Smickey }
3101e251da8Smickey 
311101ff5ddSderaadt /*
312101ff5ddSderaadt  * Search for spaces/tabs after the current word. If found, \0 the
313101ff5ddSderaadt  * first one.  Then pass a pointer to the first character of the
314101ff5ddSderaadt  * next word, or NULL if there is no next word.
315101ff5ddSderaadt  */
3161e251da8Smickey char *
nextword(char * p)317599546b3Sderaadt nextword(char *p)
3181e251da8Smickey {
319df1f5d3aSweingart 	/* skip blanks */
320101ff5ddSderaadt 	while (*p && *p != '\t' && *p != ' ')
321101ff5ddSderaadt 		p++;
322101ff5ddSderaadt 	if (*p) {
323101ff5ddSderaadt 		*p++ = '\0';
3241e251da8Smickey 		while (*p == '\t' || *p == ' ')
3251e251da8Smickey 			p++;
326101ff5ddSderaadt 	}
327101ff5ddSderaadt 	if (*p == '\0')
328101ff5ddSderaadt 		p = NULL;
3291e251da8Smickey 	return p;
330df1f5d3aSweingart }
331df1f5d3aSweingart 
332cd073bdfSmickey static void
print_help(const struct cmd_table * ct)333599546b3Sderaadt print_help(const struct cmd_table *ct)
334cd073bdfSmickey {
335cd073bdfSmickey 	for (; ct->cmd_name != NULL; ct++)
336cd073bdfSmickey 		printf(" %s", ct->cmd_name);
337cd073bdfSmickey 	putchar('\n');
338cd073bdfSmickey }
339cd073bdfSmickey 
340dc461ba4Smickey static int
Xhelp(void)341599546b3Sderaadt Xhelp(void)
342dc461ba4Smickey {
343df1f5d3aSweingart 	printf("commands:");
344cd073bdfSmickey 	print_help(cmd_table);
345cd073bdfSmickey #ifdef MACHINE_CMD
346cd073bdfSmickey 	return Xmachine();
347cd073bdfSmickey #else
348cd073bdfSmickey 	return 0;
349cd073bdfSmickey #endif
350cd073bdfSmickey }
351df1f5d3aSweingart 
3523fbdbb31Sbluhm static int
Xhexdump(void)3533fbdbb31Sbluhm Xhexdump(void)
3543fbdbb31Sbluhm {
3553fbdbb31Sbluhm 	long long val[2];
3563fbdbb31Sbluhm 	char *ep;
3573fbdbb31Sbluhm 	int i;
3583fbdbb31Sbluhm 
3593fbdbb31Sbluhm 	if (cmd.argc != 3) {
3603fbdbb31Sbluhm 		printf("hexdump addr size\n");
3613fbdbb31Sbluhm 		return 0;
3623fbdbb31Sbluhm 	}
3633fbdbb31Sbluhm 
3643fbdbb31Sbluhm 	for (i = 1; i < cmd.argc; i++) {
3653fbdbb31Sbluhm 		val[i-1] = strtoll(cmd.argv[i], &ep, 0);
3663fbdbb31Sbluhm 		if (cmd.argv[i][0] == '\0' || *ep != '\0') {
3673fbdbb31Sbluhm 			printf("bad '%c' in \"%s\"\n", *ep, cmd.argv[i]);
3683fbdbb31Sbluhm 			return 0;
3693fbdbb31Sbluhm 		}
3703fbdbb31Sbluhm 	}
3711f267e12Sderaadt 	hexdump((void *)(unsigned long)val[0], val[1]);
3723fbdbb31Sbluhm 	return 0;
3733fbdbb31Sbluhm }
3743fbdbb31Sbluhm 
375cd073bdfSmickey #ifdef MACHINE_CMD
376cd073bdfSmickey static int
Xmachine(void)377599546b3Sderaadt Xmachine(void)
378cd073bdfSmickey {
379cd073bdfSmickey 	printf("machine:");
380cd073bdfSmickey 	print_help(MACHINE_CMD);
381dc461ba4Smickey 	return 0;
382df1f5d3aSweingart }
383cd073bdfSmickey #endif
384df1f5d3aSweingart 
3855c487e4aSmickey static int
Xecho(void)386599546b3Sderaadt Xecho(void)
3875c487e4aSmickey {
388599546b3Sderaadt 	int i;
389599546b3Sderaadt 
3905c487e4aSmickey 	for (i = 1; i < cmd.argc; i++)
39138b446a2Smickey 		printf("%s ", cmd.argv[i]);
3925c487e4aSmickey 	putchar('\n');
3935c487e4aSmickey 	return 0;
3945c487e4aSmickey }
3955c487e4aSmickey 
396*a4f11372Smiod #ifdef BOOT_STTY
397dc461ba4Smickey static int
Xstty(void)398599546b3Sderaadt Xstty(void)
399e20327dbSflipk {
400599546b3Sderaadt 	int sp;
401599546b3Sderaadt 	char *cp;
40281a5a260Smickey 	dev_t dev;
40381a5a260Smickey 
404cffe3a30Stobias 	if (cmd.argc == 1) {
40581a5a260Smickey 		printf("%s speed is %d\n", ttyname(0), cnspeed(0, -1));
406cffe3a30Stobias 		return 0;
407cffe3a30Stobias 	}
40881a5a260Smickey 	dev = ttydev(cmd.argv[1]);
409cffe3a30Stobias 	if (dev == NODEV) {
41081a5a260Smickey 		printf("%s not a console device\n", cmd.argv[1]);
411cffe3a30Stobias 		return 0;
412cffe3a30Stobias 	}
413cffe3a30Stobias 
41481a5a260Smickey 	if (cmd.argc == 2)
41581a5a260Smickey 		printf("%s speed is %d\n", cmd.argv[1],
41681a5a260Smickey 		    cnspeed(dev, -1));
417e20327dbSflipk 	else {
418e20327dbSflipk 		sp = 0;
419cffe3a30Stobias 		for (cp = cmd.argv[2]; isdigit(*cp); cp++)
420e20327dbSflipk 			sp = sp * 10 + (*cp - '0');
42181a5a260Smickey 		cnspeed(dev, sp);
42281a5a260Smickey 	}
423e20327dbSflipk 	return 0;
424e20327dbSflipk }
425*a4f11372Smiod #endif
426e20327dbSflipk 
427e20327dbSflipk static int
Xtime(void)428599546b3Sderaadt Xtime(void)
42900e994b8Sweingart {
43004fbe3fcSmickey 	time_t tt = getsecs();
43104fbe3fcSmickey 
4325c487e4aSmickey 	if (cmd.argc == 1)
43304fbe3fcSmickey 		printf(ctime(&tt));
43400e994b8Sweingart 
43500e994b8Sweingart 	return 0;
43600e994b8Sweingart }
43700e994b8Sweingart 
43800e994b8Sweingart static int
Xls(void)439599546b3Sderaadt Xls(void)
440df1f5d3aSweingart {
441dc461ba4Smickey 	struct stat sb;
442599546b3Sderaadt 	char *p;
443dc461ba4Smickey 	int fd;
444dc461ba4Smickey 
4455c487e4aSmickey 	if (stat(qualify((cmd.argv[1]? cmd.argv[1]: "/.")), &sb) < 0) {
4465c487e4aSmickey 		printf("stat(%s): %s\n", cmd.path, strerror(errno));
447dc461ba4Smickey 		return 0;
448df1f5d3aSweingart 	}
449df1f5d3aSweingart 
450df1f5d3aSweingart 	if ((sb.st_mode & S_IFMT) != S_IFDIR)
4515c487e4aSmickey 		ls(cmd.path, &sb);
452df1f5d3aSweingart 	else {
4535c487e4aSmickey 		if ((fd = opendir(cmd.path)) < 0) {
4545c487e4aSmickey 			printf("opendir(%s): %s\n", cmd.path,
455dc461ba4Smickey 			    strerror(errno));
456dc461ba4Smickey 			return 0;
457df1f5d3aSweingart 		}
458df1f5d3aSweingart 
4591e251da8Smickey 		/* no strlen in lib !!! */
4601ee9984cSderaadt 		for (p = cmd.path; *p; p++)
4611ee9984cSderaadt 			;
462df1f5d3aSweingart 		*p++ = '/';
463df1f5d3aSweingart 		*p = '\0';
464df1f5d3aSweingart 
4651e251da8Smickey 		while (readdir(fd, p) >= 0) {
4665c487e4aSmickey 			if (stat(cmd.path, &sb) < 0)
4675c487e4aSmickey 				printf("stat(%s): %s\n", cmd.path,
468dc461ba4Smickey 				    strerror(errno));
4691e251da8Smickey 			else
470df1f5d3aSweingart 				ls(p, &sb);
471df1f5d3aSweingart 		}
472df1f5d3aSweingart 		closedir (fd);
473df1f5d3aSweingart 	}
474dc461ba4Smickey 	return 0;
475df1f5d3aSweingart }
476df1f5d3aSweingart 
477df1f5d3aSweingart #define lsrwx(mode,s) \
478df1f5d3aSweingart 	putchar ((mode) & S_IROTH? 'r' : '-'); \
479df1f5d3aSweingart 	putchar ((mode) & S_IWOTH? 'w' : '-'); \
480df1f5d3aSweingart 	putchar ((mode) & S_IXOTH? *(s): (s)[1]);
481df1f5d3aSweingart 
4821ad1f950Smickey static void
ls(char * name,struct stat * sb)483599546b3Sderaadt ls(char *name, struct stat *sb)
484df1f5d3aSweingart {
485df1f5d3aSweingart 	putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]);
486df1f5d3aSweingart 	lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-"));
48732031b1cSweingart 	lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-"));
488df1f5d3aSweingart 	lsrwx(sb->st_mode     , (sb->st_mode & S_ISTXT? "tT" : "x-"));
489df1f5d3aSweingart 
4901e251da8Smickey 	printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid,
4911e251da8Smickey 	    (u_long)sb->st_size, name);
492df1f5d3aSweingart }
493dc461ba4Smickey #undef lsrwx
494df1f5d3aSweingart 
4959f2d58dfSderaadt int doboot = 1;
4969f2d58dfSderaadt 
497dc461ba4Smickey static int
Xnop(void)498599546b3Sderaadt Xnop(void)
4991ee788beSweingart {
5001ee788beSweingart 	if (doboot) {
5011ee788beSweingart 		doboot = 0;
5021ee788beSweingart 		return (Xboot());
5031ee788beSweingart 	}
5041ee788beSweingart 
5051ee788beSweingart 	return 0;
5061ee788beSweingart }
5071ee788beSweingart 
5081ee788beSweingart static int
Xboot(void)509599546b3Sderaadt Xboot(void)
510dc461ba4Smickey {
5115c487e4aSmickey 	if (cmd.argc > 1 && cmd.argv[1][0] != '-') {
5125c487e4aSmickey 		qualify((cmd.argv[1]? cmd.argv[1]: cmd.image));
5135c487e4aSmickey 		if (bootparse(2))
514dc461ba4Smickey 			return 0;
515dc461ba4Smickey 	} else {
5165c487e4aSmickey 		if (bootparse(1))
517dc461ba4Smickey 			return 0;
5181ee9984cSderaadt 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
5191ee9984cSderaadt 		    cmd.bootdev, cmd.image);
520dc461ba4Smickey 	}
521dc461ba4Smickey 
522dc461ba4Smickey 	return 1;
523dc461ba4Smickey }
524dc461ba4Smickey 
5251ad1f950Smickey /*
5266957a4a4Sjmc  * Qualifies the path adding necessary dev
5271ad1f950Smickey  */
5281ad1f950Smickey 
5291ad1f950Smickey static char *
qualify(char * name)530599546b3Sderaadt qualify(char *name)
5311ad1f950Smickey {
532599546b3Sderaadt 	char *p;
5331ad1f950Smickey 
5341ad1f950Smickey 	for (p = name; *p; p++)
5351ad1f950Smickey 		if (*p == ':')
5361ad1f950Smickey 			break;
5371ad1f950Smickey 	if (*p == ':')
5381ee9984cSderaadt 		strlcpy(cmd.path, name, sizeof(cmd.path));
5391ad1f950Smickey 	else
5401ee9984cSderaadt 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
5411ee9984cSderaadt 		    cmd.bootdev, name);
5425c487e4aSmickey 	return cmd.path;
5431ad1f950Smickey }
5441ad1f950Smickey 
545dc461ba4Smickey static int
Xreboot(void)546599546b3Sderaadt Xreboot(void)
547dc461ba4Smickey {
548dc461ba4Smickey 	printf("Rebooting...\n");
549dc461ba4Smickey 	exit();
550dc461ba4Smickey 	return 0; /* just in case */
551dc461ba4Smickey }
552dc461ba4Smickey 
5534eb8cda6Sflorian int
upgrade(void)5544eb8cda6Sflorian upgrade(void)
5554eb8cda6Sflorian {
5564eb8cda6Sflorian 	struct stat sb;
5574eb8cda6Sflorian 
5584eb8cda6Sflorian 	if (stat(qualify(("/bsd.upgrade")), &sb) < 0)
5594eb8cda6Sflorian 		return 0;
560044dcf88Sderaadt 	if ((sb.st_mode & S_IXUSR) == 0) {
561044dcf88Sderaadt 		printf("/bsd.upgrade is not u+x\n");
562044dcf88Sderaadt 		return 0;
563044dcf88Sderaadt 	}
5644eb8cda6Sflorian 	return 1;
5654eb8cda6Sflorian }
566