xref: /openbsd-src/sys/arch/octeon/stand/rdboot/cmd.c (revision 57e232a594c92a7ed0574dab339eb829b8cb57fc)
1*57e232a5Smiod /*	$OpenBSD: cmd.c,v 1.5 2024/08/08 13:59:11 miod Exp $	*/
23a62b615Svisa 
33a62b615Svisa /*
43a62b615Svisa  * Copyright (c) 1997-1999 Michael Shalayeff
53a62b615Svisa  * All rights reserved.
63a62b615Svisa  *
73a62b615Svisa  * Redistribution and use in source and binary forms, with or without
83a62b615Svisa  * modification, are permitted provided that the following conditions
93a62b615Svisa  * are met:
103a62b615Svisa  * 1. Redistributions of source code must retain the above copyright
113a62b615Svisa  *    notice, this list of conditions and the following disclaimer.
123a62b615Svisa  * 2. Redistributions in binary form must reproduce the above copyright
133a62b615Svisa  *    notice, this list of conditions and the following disclaimer in the
143a62b615Svisa  *    documentation and/or other materials provided with the distribution.
153a62b615Svisa  *
163a62b615Svisa  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
173a62b615Svisa  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
183a62b615Svisa  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193a62b615Svisa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
203a62b615Svisa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213a62b615Svisa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223a62b615Svisa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233a62b615Svisa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243a62b615Svisa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253a62b615Svisa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263a62b615Svisa  * SUCH DAMAGE.
273a62b615Svisa  */
283a62b615Svisa 
293a62b615Svisa #include <sys/param.h>
303a62b615Svisa #include <sys/reboot.h>
313a62b615Svisa #include <sys/select.h>
323a62b615Svisa #include <sys/stat.h>
333a62b615Svisa 
343a62b615Svisa #include <dirent.h>
353a62b615Svisa #include <errno.h>
363a62b615Svisa #include <fcntl.h>
373a62b615Svisa #include <stdio.h>
383a62b615Svisa #include <string.h>
393a62b615Svisa #include <termios.h>
403a62b615Svisa #include <unistd.h>
413a62b615Svisa 
423a62b615Svisa #include "cmd.h"
433a62b615Svisa #include "disk.h"
443a62b615Svisa 
453a62b615Svisa static int Xboot(void);
463a62b615Svisa static int Xecho(void);
473a62b615Svisa static int Xhelp(void);
483a62b615Svisa static int Xls(void);
493a62b615Svisa static int Xnop(void);
503a62b615Svisa static int Xreboot(void);
513a62b615Svisa #ifdef MACHINE_CMD
523a62b615Svisa static int Xmachine(void);
533a62b615Svisa extern const struct cmd_table MACHINE_CMD[];
543a62b615Svisa #endif
553a62b615Svisa extern int Xset(void);
563a62b615Svisa 
573a62b615Svisa #ifdef CHECK_SKIP_CONF
583a62b615Svisa extern int CHECK_SKIP_CONF(void);
593a62b615Svisa #endif
603a62b615Svisa 
613a62b615Svisa extern const struct cmd_table cmd_set[];
623a62b615Svisa const struct cmd_table cmd_table[] = {
633a62b615Svisa 	{"#",      CMDT_CMD, Xnop},  /* XXX must be first */
643a62b615Svisa 	{"boot",   CMDT_CMD, Xboot},
653a62b615Svisa 	{"echo",   CMDT_CMD, Xecho},
663a62b615Svisa 	{"help",   CMDT_CMD, Xhelp},
673a62b615Svisa 	{"ls",     CMDT_CMD, Xls},
683a62b615Svisa #ifdef MACHINE_CMD
693a62b615Svisa 	{"machine",CMDT_MDC, Xmachine},
703a62b615Svisa #endif
713a62b615Svisa 	{"reboot", CMDT_CMD, Xreboot},
723a62b615Svisa 	{"set",    CMDT_SET, Xset},
733a62b615Svisa 	{NULL, 0},
743a62b615Svisa };
753a62b615Svisa 
763a62b615Svisa static void ls(const char *, struct stat *);
773a62b615Svisa static int readline(char *, size_t, int);
783a62b615Svisa char *nextword(char *);
793a62b615Svisa static char *whatcmd(const struct cmd_table **ct, char *);
803a62b615Svisa static char *qualify(char *);
813a62b615Svisa 
823a62b615Svisa char cmd_buf[CMD_BUFF_SIZE];
833a62b615Svisa 
843a62b615Svisa int
853a62b615Svisa getcmd(void)
863a62b615Svisa {
873a62b615Svisa 	cmd.cmd = NULL;
883a62b615Svisa 
893a62b615Svisa 	if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout))
903a62b615Svisa 		cmd.cmd = cmd_table;
913a62b615Svisa 
923a62b615Svisa 	return docmd();
933a62b615Svisa }
943a62b615Svisa 
953a62b615Svisa int
963a62b615Svisa read_conf(void)
973a62b615Svisa {
983a62b615Svisa 	struct stat sb;
993a62b615Svisa 	const char *path;
1003a62b615Svisa 	int fd, rc = 0;
1013a62b615Svisa 
1023a62b615Svisa #ifdef CHECK_SKIP_CONF
1033a62b615Svisa 	if (CHECK_SKIP_CONF()) {
1043a62b615Svisa 		printf("boot.conf processing skipped at operator request\n");
1053a62b615Svisa 		cmd.timeout = 0;
1063a62b615Svisa 		return -1;		/* Pretend file wasn't found */
1073a62b615Svisa 	}
1083a62b615Svisa #endif
1093a62b615Svisa 
1103a62b615Svisa 	path = disk_open(qualify(cmd.conf));
1113a62b615Svisa 	if (path == NULL) {
1123a62b615Svisa 		fprintf(stderr, "cannot open device for reading %s: %s\n",
1133a62b615Svisa 		    cmd.conf, strerror(errno));
1143a62b615Svisa 		return -1;
1153a62b615Svisa 	}
1163a62b615Svisa 	if ((fd = open(path, O_RDONLY)) == -1) {
1173a62b615Svisa 		if (errno != ENOENT && errno != ENXIO) {
1183a62b615Svisa 			fprintf(stderr, "%s: open(%s): %s\n", __func__,
1193a62b615Svisa 			    cmd.path, strerror(errno));
1203a62b615Svisa 			rc = 0;
1213a62b615Svisa 		} else
1223a62b615Svisa 			rc = -1;
1233a62b615Svisa 		goto out;
1243a62b615Svisa 	}
1253a62b615Svisa 
1263a62b615Svisa 	(void) fstat(fd, &sb);
1273a62b615Svisa 	if (sb.st_uid || (sb.st_mode & 2)) {
1283a62b615Svisa 		fprintf(stderr, "non-secure %s, will not proceed\n", cmd.path);
1293a62b615Svisa 		rc = -1;
1303a62b615Svisa 		goto out;
1313a62b615Svisa 	}
1323a62b615Svisa 
1333a62b615Svisa 	do {
1343a62b615Svisa 		char *p = cmd_buf;
1353a62b615Svisa 
1363a62b615Svisa 		cmd.cmd = NULL;
1373a62b615Svisa 		do {
1383a62b615Svisa 			rc = read(fd, p, 1);
1393a62b615Svisa 		} while (rc > 0 && *p++ != '\n' &&
1403a62b615Svisa 		    (p-cmd_buf) < sizeof(cmd_buf));
1413a62b615Svisa 
1423a62b615Svisa 		if (rc < 0) {			/* Error from read() */
1433a62b615Svisa 			fprintf(stderr, "%s: %s\n", cmd.path, strerror(errno));
1443a62b615Svisa 			break;
1453a62b615Svisa 		}
1463a62b615Svisa 
1473a62b615Svisa 		if (rc == 0) {			/* eof from read() */
1483a62b615Svisa 			if (p != cmd_buf) {	/* Line w/o trailing \n */
1493a62b615Svisa 				*p = '\0';
1503a62b615Svisa 				rc = docmd();
1513a62b615Svisa 				break;
1523a62b615Svisa 			}
1533a62b615Svisa 		} else {			/* rc > 0, read a char */
1543a62b615Svisa 			p--;			/* Get back to last character */
1553a62b615Svisa 
1563a62b615Svisa 			if (*p != '\n') {	/* Line was too long */
1573a62b615Svisa 				fprintf(stderr, "%s: line too long\n",
1583a62b615Svisa 				    cmd.path);
1593a62b615Svisa 
1603a62b615Svisa 				/* Don't want to run the truncated command */
1613a62b615Svisa 				rc = -1;
1623a62b615Svisa 			}
1633a62b615Svisa 			*p = '\0';
1643a62b615Svisa 		}
1653a62b615Svisa 	} while (rc > 0 && !(rc = docmd()));
1663a62b615Svisa 
1673a62b615Svisa out:
1683a62b615Svisa 	if (fd != -1)
1693a62b615Svisa 		close(fd);
1703a62b615Svisa 	disk_close();
1713a62b615Svisa 	return rc;
1723a62b615Svisa }
1733a62b615Svisa 
1743a62b615Svisa int
1753a62b615Svisa docmd(void)
1763a62b615Svisa {
1773a62b615Svisa 	char *p = NULL;
1783a62b615Svisa 	const struct cmd_table *ct = cmd_table, *cs;
1793a62b615Svisa 
1803a62b615Svisa 	cmd.argc = 1;
1813a62b615Svisa 	if (cmd.cmd == NULL) {
1823a62b615Svisa 
1833a62b615Svisa 		/* command */
1843a62b615Svisa 		for (p = cmd_buf; *p == ' ' || *p == '\t'; p++)
1853a62b615Svisa 			;
1863a62b615Svisa 		if (*p == '#' || *p == '\0') { /* comment or empty string */
1873a62b615Svisa #ifdef DEBUG
1883a62b615Svisa 			printf("rem\n");
1893a62b615Svisa #endif
1903a62b615Svisa 			return 0;
1913a62b615Svisa 		}
1923a62b615Svisa 		ct = cmd_table;
1933a62b615Svisa 		cs = NULL;
1943a62b615Svisa 		cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */
1953a62b615Svisa 		p = whatcmd(&ct, p);
1963a62b615Svisa 		if (ct == NULL) {
1973a62b615Svisa 			cmd.argc++;
1983a62b615Svisa 			ct = cmd_table;
1993a62b615Svisa 		} else if (ct->cmd_type == CMDT_SET && p != NULL) {
2003a62b615Svisa 			cs = cmd_set;
2013a62b615Svisa #ifdef MACHINE_CMD
2023a62b615Svisa 		} else if (ct->cmd_type == CMDT_MDC && p != NULL) {
2033a62b615Svisa 			cs = MACHINE_CMD;
2043a62b615Svisa #endif
2053a62b615Svisa 		}
2063a62b615Svisa 
2073a62b615Svisa 		if (cs != NULL) {
2083a62b615Svisa 			p = whatcmd(&cs, p);
2093a62b615Svisa 			if (cs == NULL) {
2103a62b615Svisa 				printf("%s: syntax error\n", ct->cmd_name);
2113a62b615Svisa 				return 0;
2123a62b615Svisa 			}
2133a62b615Svisa 			ct = cs;
2143a62b615Svisa 		}
2153a62b615Svisa 		cmd.cmd = ct;
2163a62b615Svisa 	}
2173a62b615Svisa 
2183a62b615Svisa 	cmd.argv[0] = ct->cmd_name;
2193a62b615Svisa 	while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) {
2203a62b615Svisa 		cmd.argv[cmd.argc++] = p;
2213a62b615Svisa 		p = nextword(p);
2223a62b615Svisa 	}
2233a62b615Svisa 	cmd.argv[cmd.argc] = NULL;
2243a62b615Svisa 
2253a62b615Svisa 	return (*cmd.cmd->cmd_exec)();
2263a62b615Svisa }
2273a62b615Svisa 
2283a62b615Svisa static char *
2293a62b615Svisa whatcmd(const struct cmd_table **ct, char *p)
2303a62b615Svisa {
2313a62b615Svisa 	char *q;
2323a62b615Svisa 	int l;
2333a62b615Svisa 
2343a62b615Svisa 	q = nextword(p);
2353a62b615Svisa 
2363a62b615Svisa 	for (l = 0; p[l]; l++)
2373a62b615Svisa 		;
2383a62b615Svisa 
2393a62b615Svisa 	while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l))
2403a62b615Svisa 		(*ct)++;
2413a62b615Svisa 
2423a62b615Svisa 	if ((*ct)->cmd_name == NULL)
2433a62b615Svisa 		*ct = NULL;
2443a62b615Svisa 
2453a62b615Svisa 	return q;
2463a62b615Svisa }
2473a62b615Svisa 
2483a62b615Svisa static int
2493a62b615Svisa readline(char *buf, size_t n, int to)
2503a62b615Svisa {
2513a62b615Svisa 	struct termios saved_tio, tio;
2523a62b615Svisa 	struct timeval tv;
2533a62b615Svisa 	fd_set fdset;
254dd20b077Svisa 	char *p;
2553a62b615Svisa 	int timed_out = 0;
2563a62b615Svisa #ifdef DEBUG
2573a62b615Svisa 	extern int debug;
2583a62b615Svisa #endif
2593a62b615Svisa 
2603a62b615Svisa 	/* Only do timeout if greater than 0 */
2613a62b615Svisa 	if (to > 0) {
2623a62b615Svisa 		/* Switch to non-canonical mode for timeout detection. */
2633a62b615Svisa 		tcgetattr(STDIN_FILENO, &saved_tio);
2643a62b615Svisa 		tio = saved_tio;
2653a62b615Svisa 		tio.c_lflag &= ~(ECHO | ICANON);
2663a62b615Svisa 		tcsetattr(STDIN_FILENO, TCSANOW, &tio);
2673a62b615Svisa 
2683a62b615Svisa 		FD_ZERO(&fdset);
2693a62b615Svisa 		FD_SET(STDIN_FILENO, &fdset);
2703a62b615Svisa 		tv.tv_sec = to;
2713a62b615Svisa 		tv.tv_usec = 0;
2723a62b615Svisa 		if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, &tv) == 0)
2733a62b615Svisa 			timed_out = 1;
2743a62b615Svisa 
2753a62b615Svisa 		/* Restore canonical mode. */
2763a62b615Svisa 		tcsetattr(STDIN_FILENO, TCSANOW, &saved_tio);
2773a62b615Svisa 
2783a62b615Svisa 		if (timed_out) {
2793a62b615Svisa 			strlcpy(buf, "boot", 5);
2803a62b615Svisa 			putchar('\n');
2813a62b615Svisa 			return strlen(buf);
2823a62b615Svisa 		}
2833a62b615Svisa 	}
2843a62b615Svisa 
2853a62b615Svisa 	/* User has typed something.  Turn off timeouts. */
2863a62b615Svisa 	cmd.timeout = 0;
2873a62b615Svisa 
2883a62b615Svisa 	if (fgets(buf, n, stdin) == NULL)
2893a62b615Svisa 		return 0;
2903a62b615Svisa 
2913a62b615Svisa 	/* Strip trailing newline. */
292dd20b077Svisa 	p = strchr(buf, '\n');
293dd20b077Svisa 	if (p != NULL)
294dd20b077Svisa 		*p = '\0';
2953a62b615Svisa 
2963a62b615Svisa 	return strlen(buf);
2973a62b615Svisa }
2983a62b615Svisa 
2993a62b615Svisa /*
3003a62b615Svisa  * Search for spaces/tabs after the current word. If found, \0 the
3013a62b615Svisa  * first one.  Then pass a pointer to the first character of the
3023a62b615Svisa  * next word, or NULL if there is no next word.
3033a62b615Svisa  */
3043a62b615Svisa char *
3053a62b615Svisa nextword(char *p)
3063a62b615Svisa {
3073a62b615Svisa 	/* skip blanks */
3083a62b615Svisa 	while (*p && *p != '\t' && *p != ' ')
3093a62b615Svisa 		p++;
3103a62b615Svisa 	if (*p) {
3113a62b615Svisa 		*p++ = '\0';
3123a62b615Svisa 		while (*p == '\t' || *p == ' ')
3133a62b615Svisa 			p++;
3143a62b615Svisa 	}
3153a62b615Svisa 	if (*p == '\0')
3163a62b615Svisa 		p = NULL;
3173a62b615Svisa 	return p;
3183a62b615Svisa }
3193a62b615Svisa 
3203a62b615Svisa static void
3213a62b615Svisa print_help(const struct cmd_table *ct)
3223a62b615Svisa {
3233a62b615Svisa 	for (; ct->cmd_name != NULL; ct++)
3243a62b615Svisa 		printf(" %s", ct->cmd_name);
3253a62b615Svisa 	putchar('\n');
3263a62b615Svisa }
3273a62b615Svisa 
3283a62b615Svisa static int
3293a62b615Svisa Xhelp(void)
3303a62b615Svisa {
3313a62b615Svisa 	printf("commands:");
3323a62b615Svisa 	print_help(cmd_table);
3333a62b615Svisa #ifdef MACHINE_CMD
3343a62b615Svisa 	return Xmachine();
3353a62b615Svisa #else
3363a62b615Svisa 	return 0;
3373a62b615Svisa #endif
3383a62b615Svisa }
3393a62b615Svisa 
3403a62b615Svisa #ifdef MACHINE_CMD
3413a62b615Svisa static int
3423a62b615Svisa Xmachine(void)
3433a62b615Svisa {
3443a62b615Svisa 	printf("machine:");
3453a62b615Svisa 	print_help(MACHINE_CMD);
3463a62b615Svisa 	return 0;
3473a62b615Svisa }
3483a62b615Svisa #endif
3493a62b615Svisa 
3503a62b615Svisa static int
3513a62b615Svisa Xecho(void)
3523a62b615Svisa {
3533a62b615Svisa 	int i;
3543a62b615Svisa 
3553a62b615Svisa 	for (i = 1; i < cmd.argc; i++)
3563a62b615Svisa 		printf("%s ", cmd.argv[i]);
3573a62b615Svisa 	putchar('\n');
3583a62b615Svisa 	return 0;
3593a62b615Svisa }
3603a62b615Svisa 
3613a62b615Svisa static int
3623a62b615Svisa Xls(void)
3633a62b615Svisa {
3643a62b615Svisa 	struct stat sb;
3653a62b615Svisa 	const char *path;
3663a62b615Svisa 	DIR *dir;
3673a62b615Svisa 	struct dirent *dent;
3683a62b615Svisa 	int dirfd, oldcwd;
3693a62b615Svisa 
3703a62b615Svisa 	path = disk_open(qualify(cmd.argv[1] ? cmd.argv[1] : "/."));
3713a62b615Svisa 	if (path == NULL)
3723a62b615Svisa 		return 0;
3733a62b615Svisa 
3743a62b615Svisa 	if (stat(path, &sb) < 0) {
3753a62b615Svisa 		printf("stat(%s): %s\n", cmd.path, strerror(errno));
3763a62b615Svisa 		goto out;
3773a62b615Svisa 	}
3783a62b615Svisa 
3793a62b615Svisa 	if ((sb.st_mode & S_IFMT) != S_IFDIR)
3803a62b615Svisa 		ls(path, &sb);
3813a62b615Svisa 	else {
3823a62b615Svisa 		oldcwd = open(".", O_RDONLY);
3833a62b615Svisa 
3843a62b615Svisa 		dirfd = open(path, O_RDONLY);
3853a62b615Svisa 		if (dirfd < 0) {
3863a62b615Svisa 			printf("opendir(%s): %s\n", cmd.path, strerror(errno));
3873a62b615Svisa 			close(oldcwd);
3883a62b615Svisa 			goto out;
3893a62b615Svisa 		}
3903a62b615Svisa 		if ((dir = fdopendir(dirfd)) < 0) {
3913a62b615Svisa 			printf("opendir(%s): %s\n", cmd.path, strerror(errno));
3923a62b615Svisa 			close(dirfd);
3933a62b615Svisa 			close(oldcwd);
3943a62b615Svisa 			goto out;
3953a62b615Svisa 		}
3963a62b615Svisa 		fchdir(dirfd);
3973a62b615Svisa 		while ((dent = readdir(dir)) != NULL) {
3983a62b615Svisa 			if (fstatat(dirfd, dent->d_name, &sb,
3993a62b615Svisa 			    AT_SYMLINK_NOFOLLOW) < 0)
4003a62b615Svisa 				printf("stat(%s): %s\n", dent->d_name,
4013a62b615Svisa 				    strerror(errno));
4023a62b615Svisa 			else
4033a62b615Svisa 				ls(dent->d_name, &sb);
4043a62b615Svisa 		}
4053a62b615Svisa 		closedir(dir);
4063a62b615Svisa 
4073a62b615Svisa 		fchdir(oldcwd);
40800803372Svisa 		close(oldcwd);
4093a62b615Svisa 	}
4103a62b615Svisa 
4113a62b615Svisa out:
4123a62b615Svisa 	disk_close();
4133a62b615Svisa 	return 0;
4143a62b615Svisa }
4153a62b615Svisa 
4163a62b615Svisa #define lsrwx(mode,s) \
4173a62b615Svisa 	putchar ((mode) & S_IROTH? 'r' : '-'); \
4183a62b615Svisa 	putchar ((mode) & S_IWOTH? 'w' : '-'); \
4193a62b615Svisa 	putchar ((mode) & S_IXOTH? *(s): (s)[1]);
4203a62b615Svisa 
4213a62b615Svisa static void
4223a62b615Svisa ls(const char *name, struct stat *sb)
4233a62b615Svisa {
4243a62b615Svisa 	putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]);
4253a62b615Svisa 	lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-"));
4263a62b615Svisa 	lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-"));
4273a62b615Svisa 	lsrwx(sb->st_mode     , (sb->st_mode & S_ISTXT? "tT" : "x-"));
4283a62b615Svisa 
4293a62b615Svisa 	printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid,
4303a62b615Svisa 	    (u_long)sb->st_size, name);
4313a62b615Svisa }
4323a62b615Svisa #undef lsrwx
4333a62b615Svisa 
4343a62b615Svisa int doboot = 1;
4353a62b615Svisa 
4363a62b615Svisa static int
4373a62b615Svisa Xnop(void)
4383a62b615Svisa {
4393a62b615Svisa 	if (doboot) {
4403a62b615Svisa 		doboot = 0;
4413a62b615Svisa 		return (Xboot());
4423a62b615Svisa 	}
4433a62b615Svisa 
4443a62b615Svisa 	return 0;
4453a62b615Svisa }
4463a62b615Svisa 
4473a62b615Svisa static int
4483a62b615Svisa Xboot(void)
4493a62b615Svisa {
4503a62b615Svisa 	if (cmd.argc > 1 && cmd.argv[1][0] != '-') {
4513a62b615Svisa 		qualify((cmd.argv[1]? cmd.argv[1]: cmd.image));
4523a62b615Svisa 		if (bootparse(2))
4533a62b615Svisa 			return 0;
4543a62b615Svisa 	} else {
4553a62b615Svisa 		if (bootparse(1))
4563a62b615Svisa 			return 0;
4573a62b615Svisa 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
4583a62b615Svisa 		    cmd.bootdev, cmd.image);
4593a62b615Svisa 	}
4603a62b615Svisa 
4613a62b615Svisa 	return 1;
4623a62b615Svisa }
4633a62b615Svisa 
4643a62b615Svisa /*
4653a62b615Svisa  * Qualifies the path adding necessary dev
4663a62b615Svisa  */
4673a62b615Svisa 
4683a62b615Svisa static char *
4693a62b615Svisa qualify(char *name)
4703a62b615Svisa {
4713a62b615Svisa 	char *p;
4723a62b615Svisa 
4733a62b615Svisa 	for (p = name; *p; p++)
4743a62b615Svisa 		if (*p == ':')
4753a62b615Svisa 			break;
4763a62b615Svisa 	if (*p == ':')
4773a62b615Svisa 		strlcpy(cmd.path, name, sizeof(cmd.path));
4783a62b615Svisa 	else
4793a62b615Svisa 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
4803a62b615Svisa 		    cmd.bootdev, name);
4813a62b615Svisa 	return cmd.path;
4823a62b615Svisa }
4833a62b615Svisa 
4843a62b615Svisa static int
4853a62b615Svisa Xreboot(void)
4863a62b615Svisa {
4873a62b615Svisa 	printf("Rebooting...\n");
4883a62b615Svisa 	reboot(0);
4893a62b615Svisa 	return 0; /* just in case */
4903a62b615Svisa }
4913a62b615Svisa 
4923a62b615Svisa int
4933a62b615Svisa upgrade(void)
4943a62b615Svisa {
4953a62b615Svisa 	struct stat sb;
4963a62b615Svisa 	const char *path;
4973a62b615Svisa 	int ret = 0;
4983a62b615Svisa 
4993a62b615Svisa 	path = disk_open(qualify("/bsd.upgrade"));
5003a62b615Svisa 	if (path == NULL)
5013a62b615Svisa 		return 0;
502*57e232a5Smiod 	if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)) {
5033a62b615Svisa 		ret = 1;
504d807f41cSkn 		if ((sb.st_mode & S_IXUSR) == 0) {
505d807f41cSkn 			printf("/bsd.upgrade is not u+x\n");
506d807f41cSkn 			ret = 0;
507d807f41cSkn 		}
508*57e232a5Smiod 	}
5093a62b615Svisa 	disk_close();
5103a62b615Svisa 
5113a62b615Svisa 	return ret;
5123a62b615Svisa }
513