xref: /openbsd-src/sys/arch/powerpc64/stand/rdboot/cmd.c (revision 57e232a594c92a7ed0574dab339eb829b8cb57fc)
1*57e232a5Smiod /*	$OpenBSD: cmd.c,v 1.3 2024/08/08 13:59:11 miod Exp $	*/
2a79842c9Skettenis 
3a79842c9Skettenis /*
4a79842c9Skettenis  * Copyright (c) 1997-1999 Michael Shalayeff
5a79842c9Skettenis  * All rights reserved.
6a79842c9Skettenis  *
7a79842c9Skettenis  * Redistribution and use in source and binary forms, with or without
8a79842c9Skettenis  * modification, are permitted provided that the following conditions
9a79842c9Skettenis  * are met:
10a79842c9Skettenis  * 1. Redistributions of source code must retain the above copyright
11a79842c9Skettenis  *    notice, this list of conditions and the following disclaimer.
12a79842c9Skettenis  * 2. Redistributions in binary form must reproduce the above copyright
13a79842c9Skettenis  *    notice, this list of conditions and the following disclaimer in the
14a79842c9Skettenis  *    documentation and/or other materials provided with the distribution.
15a79842c9Skettenis  *
16a79842c9Skettenis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17a79842c9Skettenis  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18a79842c9Skettenis  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a79842c9Skettenis  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20a79842c9Skettenis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a79842c9Skettenis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a79842c9Skettenis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a79842c9Skettenis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a79842c9Skettenis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a79842c9Skettenis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a79842c9Skettenis  * SUCH DAMAGE.
27a79842c9Skettenis  */
28a79842c9Skettenis 
29a79842c9Skettenis #include <sys/param.h>
30a79842c9Skettenis #include <sys/reboot.h>
31a79842c9Skettenis #include <sys/select.h>
32a79842c9Skettenis #include <sys/stat.h>
33a79842c9Skettenis 
34a79842c9Skettenis #include <dirent.h>
35a79842c9Skettenis #include <errno.h>
36a79842c9Skettenis #include <fcntl.h>
37a79842c9Skettenis #include <stdio.h>
38a79842c9Skettenis #include <string.h>
39a79842c9Skettenis #include <termios.h>
40a79842c9Skettenis #include <unistd.h>
41a79842c9Skettenis 
42a79842c9Skettenis #include "cmd.h"
43a79842c9Skettenis #include "disk.h"
44a79842c9Skettenis 
45a79842c9Skettenis static int Xboot(void);
46a79842c9Skettenis static int Xecho(void);
47a79842c9Skettenis static int Xhelp(void);
48a79842c9Skettenis static int Xls(void);
49a79842c9Skettenis static int Xnop(void);
50a79842c9Skettenis static int Xreboot(void);
51a79842c9Skettenis #ifdef MACHINE_CMD
52a79842c9Skettenis static int Xmachine(void);
53a79842c9Skettenis extern const struct cmd_table MACHINE_CMD[];
54a79842c9Skettenis #endif
55a79842c9Skettenis extern int Xset(void);
56a79842c9Skettenis 
57a79842c9Skettenis #ifdef CHECK_SKIP_CONF
58a79842c9Skettenis extern int CHECK_SKIP_CONF(void);
59a79842c9Skettenis #endif
60a79842c9Skettenis 
61a79842c9Skettenis extern const struct cmd_table cmd_set[];
62a79842c9Skettenis const struct cmd_table cmd_table[] = {
63a79842c9Skettenis 	{"#",      CMDT_CMD, Xnop},  /* XXX must be first */
64a79842c9Skettenis 	{"boot",   CMDT_CMD, Xboot},
65a79842c9Skettenis 	{"echo",   CMDT_CMD, Xecho},
66a79842c9Skettenis 	{"help",   CMDT_CMD, Xhelp},
67a79842c9Skettenis 	{"ls",     CMDT_CMD, Xls},
68a79842c9Skettenis #ifdef MACHINE_CMD
69a79842c9Skettenis 	{"machine",CMDT_MDC, Xmachine},
70a79842c9Skettenis #endif
71a79842c9Skettenis 	{"reboot", CMDT_CMD, Xreboot},
72a79842c9Skettenis 	{"set",    CMDT_SET, Xset},
73a79842c9Skettenis 	{NULL, 0},
74a79842c9Skettenis };
75a79842c9Skettenis 
76a79842c9Skettenis static void ls(const char *, struct stat *);
77a79842c9Skettenis static int readline(char *, size_t, int);
78a79842c9Skettenis char *nextword(char *);
79a79842c9Skettenis static char *whatcmd(const struct cmd_table **ct, char *);
80a79842c9Skettenis static char *qualify(char *);
81a79842c9Skettenis 
82a79842c9Skettenis char cmd_buf[CMD_BUFF_SIZE];
83a79842c9Skettenis 
84a79842c9Skettenis int
85a79842c9Skettenis getcmd(void)
86a79842c9Skettenis {
87a79842c9Skettenis 	cmd.cmd = NULL;
88a79842c9Skettenis 
89a79842c9Skettenis 	if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout))
90a79842c9Skettenis 		cmd.cmd = cmd_table;
91a79842c9Skettenis 
92a79842c9Skettenis 	return docmd();
93a79842c9Skettenis }
94a79842c9Skettenis 
95a79842c9Skettenis int
96a79842c9Skettenis read_conf(void)
97a79842c9Skettenis {
98a79842c9Skettenis 	struct stat sb;
99a79842c9Skettenis 	const char *path;
100a79842c9Skettenis 	int fd, rc = 0;
101a79842c9Skettenis 
102a79842c9Skettenis #ifdef CHECK_SKIP_CONF
103a79842c9Skettenis 	if (CHECK_SKIP_CONF()) {
104a79842c9Skettenis 		printf("boot.conf processing skipped at operator request\n");
105a79842c9Skettenis 		cmd.timeout = 0;
106a79842c9Skettenis 		return -1;		/* Pretend file wasn't found */
107a79842c9Skettenis 	}
108a79842c9Skettenis #endif
109a79842c9Skettenis 
110a79842c9Skettenis 	path = disk_open(qualify(cmd.conf));
111a79842c9Skettenis 	if (path == NULL) {
112a79842c9Skettenis 		fprintf(stderr, "cannot open device for reading %s: %s\n",
113a79842c9Skettenis 		    cmd.conf, strerror(errno));
114a79842c9Skettenis 		return -1;
115a79842c9Skettenis 	}
116a79842c9Skettenis 	if ((fd = open(path, O_RDONLY)) == -1) {
117a79842c9Skettenis 		if (errno != ENOENT && errno != ENXIO) {
118a79842c9Skettenis 			fprintf(stderr, "%s: open(%s): %s\n", __func__,
119a79842c9Skettenis 			    cmd.path, strerror(errno));
120a79842c9Skettenis 			rc = 0;
121a79842c9Skettenis 		} else
122a79842c9Skettenis 			rc = -1;
123a79842c9Skettenis 		goto out;
124a79842c9Skettenis 	}
125a79842c9Skettenis 
126a79842c9Skettenis 	(void) fstat(fd, &sb);
127a79842c9Skettenis 	if (sb.st_uid || (sb.st_mode & 2)) {
128a79842c9Skettenis 		fprintf(stderr, "non-secure %s, will not proceed\n", cmd.path);
129a79842c9Skettenis 		rc = -1;
130a79842c9Skettenis 		goto out;
131a79842c9Skettenis 	}
132a79842c9Skettenis 
133a79842c9Skettenis 	do {
134a79842c9Skettenis 		char *p = cmd_buf;
135a79842c9Skettenis 
136a79842c9Skettenis 		cmd.cmd = NULL;
137a79842c9Skettenis 		do {
138a79842c9Skettenis 			rc = read(fd, p, 1);
139a79842c9Skettenis 		} while (rc > 0 && *p++ != '\n' &&
140a79842c9Skettenis 		    (p-cmd_buf) < sizeof(cmd_buf));
141a79842c9Skettenis 
142a79842c9Skettenis 		if (rc < 0) {			/* Error from read() */
143a79842c9Skettenis 			fprintf(stderr, "%s: %s\n", cmd.path, strerror(errno));
144a79842c9Skettenis 			break;
145a79842c9Skettenis 		}
146a79842c9Skettenis 
147a79842c9Skettenis 		if (rc == 0) {			/* eof from read() */
148a79842c9Skettenis 			if (p != cmd_buf) {	/* Line w/o trailing \n */
149a79842c9Skettenis 				*p = '\0';
150a79842c9Skettenis 				rc = docmd();
151a79842c9Skettenis 				break;
152a79842c9Skettenis 			}
153a79842c9Skettenis 		} else {			/* rc > 0, read a char */
154a79842c9Skettenis 			p--;			/* Get back to last character */
155a79842c9Skettenis 
156a79842c9Skettenis 			if (*p != '\n') {	/* Line was too long */
157a79842c9Skettenis 				fprintf(stderr, "%s: line too long\n",
158a79842c9Skettenis 				    cmd.path);
159a79842c9Skettenis 
160a79842c9Skettenis 				/* Don't want to run the truncated command */
161a79842c9Skettenis 				rc = -1;
162a79842c9Skettenis 			}
163a79842c9Skettenis 			*p = '\0';
164a79842c9Skettenis 		}
165a79842c9Skettenis 	} while (rc > 0 && !(rc = docmd()));
166a79842c9Skettenis 
167a79842c9Skettenis out:
168a79842c9Skettenis 	if (fd != -1)
169a79842c9Skettenis 		close(fd);
170a79842c9Skettenis 	disk_close();
171a79842c9Skettenis 	return rc;
172a79842c9Skettenis }
173a79842c9Skettenis 
174a79842c9Skettenis int
175a79842c9Skettenis docmd(void)
176a79842c9Skettenis {
177a79842c9Skettenis 	char *p = NULL;
178a79842c9Skettenis 	const struct cmd_table *ct = cmd_table, *cs;
179a79842c9Skettenis 
180a79842c9Skettenis 	cmd.argc = 1;
181a79842c9Skettenis 	if (cmd.cmd == NULL) {
182a79842c9Skettenis 
183a79842c9Skettenis 		/* command */
184a79842c9Skettenis 		for (p = cmd_buf; *p == ' ' || *p == '\t'; p++)
185a79842c9Skettenis 			;
186a79842c9Skettenis 		if (*p == '#' || *p == '\0') { /* comment or empty string */
187a79842c9Skettenis #ifdef DEBUG
188a79842c9Skettenis 			printf("rem\n");
189a79842c9Skettenis #endif
190a79842c9Skettenis 			return 0;
191a79842c9Skettenis 		}
192a79842c9Skettenis 		ct = cmd_table;
193a79842c9Skettenis 		cs = NULL;
194a79842c9Skettenis 		cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */
195a79842c9Skettenis 		p = whatcmd(&ct, p);
196a79842c9Skettenis 		if (ct == NULL) {
197a79842c9Skettenis 			cmd.argc++;
198a79842c9Skettenis 			ct = cmd_table;
199a79842c9Skettenis 		} else if (ct->cmd_type == CMDT_SET && p != NULL) {
200a79842c9Skettenis 			cs = cmd_set;
201a79842c9Skettenis #ifdef MACHINE_CMD
202a79842c9Skettenis 		} else if (ct->cmd_type == CMDT_MDC && p != NULL) {
203a79842c9Skettenis 			cs = MACHINE_CMD;
204a79842c9Skettenis #endif
205a79842c9Skettenis 		}
206a79842c9Skettenis 
207a79842c9Skettenis 		if (cs != NULL) {
208a79842c9Skettenis 			p = whatcmd(&cs, p);
209a79842c9Skettenis 			if (cs == NULL) {
210a79842c9Skettenis 				printf("%s: syntax error\n", ct->cmd_name);
211a79842c9Skettenis 				return 0;
212a79842c9Skettenis 			}
213a79842c9Skettenis 			ct = cs;
214a79842c9Skettenis 		}
215a79842c9Skettenis 		cmd.cmd = ct;
216a79842c9Skettenis 	}
217a79842c9Skettenis 
218a79842c9Skettenis 	cmd.argv[0] = ct->cmd_name;
219a79842c9Skettenis 	while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) {
220a79842c9Skettenis 		cmd.argv[cmd.argc++] = p;
221a79842c9Skettenis 		p = nextword(p);
222a79842c9Skettenis 	}
223a79842c9Skettenis 	cmd.argv[cmd.argc] = NULL;
224a79842c9Skettenis 
225a79842c9Skettenis 	return (*cmd.cmd->cmd_exec)();
226a79842c9Skettenis }
227a79842c9Skettenis 
228a79842c9Skettenis static char *
229a79842c9Skettenis whatcmd(const struct cmd_table **ct, char *p)
230a79842c9Skettenis {
231a79842c9Skettenis 	char *q;
232a79842c9Skettenis 	int l;
233a79842c9Skettenis 
234a79842c9Skettenis 	q = nextword(p);
235a79842c9Skettenis 
236a79842c9Skettenis 	for (l = 0; p[l]; l++)
237a79842c9Skettenis 		;
238a79842c9Skettenis 
239a79842c9Skettenis 	while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l))
240a79842c9Skettenis 		(*ct)++;
241a79842c9Skettenis 
242a79842c9Skettenis 	if ((*ct)->cmd_name == NULL)
243a79842c9Skettenis 		*ct = NULL;
244a79842c9Skettenis 
245a79842c9Skettenis 	return q;
246a79842c9Skettenis }
247a79842c9Skettenis 
248a79842c9Skettenis static int
249a79842c9Skettenis readline(char *buf, size_t n, int to)
250a79842c9Skettenis {
251a79842c9Skettenis 	struct termios saved_tio, tio;
252a79842c9Skettenis 	struct timeval tv;
253a79842c9Skettenis 	fd_set fdset;
254a79842c9Skettenis 	char *p;
255a79842c9Skettenis 	int timed_out = 0;
256a79842c9Skettenis #ifdef DEBUG
257a79842c9Skettenis 	extern int debug;
258a79842c9Skettenis #endif
259a79842c9Skettenis 
260a79842c9Skettenis 	/* Only do timeout if greater than 0 */
261a79842c9Skettenis 	if (to > 0) {
262a79842c9Skettenis 		/* Switch to non-canonical mode for timeout detection. */
263a79842c9Skettenis 		tcgetattr(STDIN_FILENO, &saved_tio);
264a79842c9Skettenis 		tio = saved_tio;
265a79842c9Skettenis 		tio.c_lflag &= ~(ECHO | ICANON);
266a79842c9Skettenis 		tcsetattr(STDIN_FILENO, TCSANOW, &tio);
267a79842c9Skettenis 
268a79842c9Skettenis 		FD_ZERO(&fdset);
269a79842c9Skettenis 		FD_SET(STDIN_FILENO, &fdset);
270a79842c9Skettenis 		tv.tv_sec = to;
271a79842c9Skettenis 		tv.tv_usec = 0;
272a79842c9Skettenis 		if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, &tv) == 0)
273a79842c9Skettenis 			timed_out = 1;
274a79842c9Skettenis 
275a79842c9Skettenis 		/* Restore canonical mode. */
276a79842c9Skettenis 		tcsetattr(STDIN_FILENO, TCSANOW, &saved_tio);
277a79842c9Skettenis 
278a79842c9Skettenis 		if (timed_out) {
279a79842c9Skettenis 			strlcpy(buf, "boot", 5);
280a79842c9Skettenis 			putchar('\n');
281a79842c9Skettenis 			return strlen(buf);
282a79842c9Skettenis 		}
283a79842c9Skettenis 	}
284a79842c9Skettenis 
285a79842c9Skettenis 	/* User has typed something.  Turn off timeouts. */
286a79842c9Skettenis 	cmd.timeout = 0;
287a79842c9Skettenis 
288a79842c9Skettenis 	if (fgets(buf, n, stdin) == NULL)
289a79842c9Skettenis 		return 0;
290a79842c9Skettenis 
291a79842c9Skettenis 	/* Strip trailing newline. */
292a79842c9Skettenis 	p = strchr(buf, '\n');
293a79842c9Skettenis 	if (p != NULL)
294a79842c9Skettenis 		*p = '\0';
295a79842c9Skettenis 
296a79842c9Skettenis 	return strlen(buf);
297a79842c9Skettenis }
298a79842c9Skettenis 
299a79842c9Skettenis /*
300a79842c9Skettenis  * Search for spaces/tabs after the current word. If found, \0 the
301a79842c9Skettenis  * first one.  Then pass a pointer to the first character of the
302a79842c9Skettenis  * next word, or NULL if there is no next word.
303a79842c9Skettenis  */
304a79842c9Skettenis char *
305a79842c9Skettenis nextword(char *p)
306a79842c9Skettenis {
307a79842c9Skettenis 	/* skip blanks */
308a79842c9Skettenis 	while (*p && *p != '\t' && *p != ' ')
309a79842c9Skettenis 		p++;
310a79842c9Skettenis 	if (*p) {
311a79842c9Skettenis 		*p++ = '\0';
312a79842c9Skettenis 		while (*p == '\t' || *p == ' ')
313a79842c9Skettenis 			p++;
314a79842c9Skettenis 	}
315a79842c9Skettenis 	if (*p == '\0')
316a79842c9Skettenis 		p = NULL;
317a79842c9Skettenis 	return p;
318a79842c9Skettenis }
319a79842c9Skettenis 
320a79842c9Skettenis static void
321a79842c9Skettenis print_help(const struct cmd_table *ct)
322a79842c9Skettenis {
323a79842c9Skettenis 	for (; ct->cmd_name != NULL; ct++)
324a79842c9Skettenis 		printf(" %s", ct->cmd_name);
325a79842c9Skettenis 	putchar('\n');
326a79842c9Skettenis }
327a79842c9Skettenis 
328a79842c9Skettenis static int
329a79842c9Skettenis Xhelp(void)
330a79842c9Skettenis {
331a79842c9Skettenis 	printf("commands:");
332a79842c9Skettenis 	print_help(cmd_table);
333a79842c9Skettenis #ifdef MACHINE_CMD
334a79842c9Skettenis 	return Xmachine();
335a79842c9Skettenis #else
336a79842c9Skettenis 	return 0;
337a79842c9Skettenis #endif
338a79842c9Skettenis }
339a79842c9Skettenis 
340a79842c9Skettenis #ifdef MACHINE_CMD
341a79842c9Skettenis static int
342a79842c9Skettenis Xmachine(void)
343a79842c9Skettenis {
344a79842c9Skettenis 	printf("machine:");
345a79842c9Skettenis 	print_help(MACHINE_CMD);
346a79842c9Skettenis 	return 0;
347a79842c9Skettenis }
348a79842c9Skettenis #endif
349a79842c9Skettenis 
350a79842c9Skettenis static int
351a79842c9Skettenis Xecho(void)
352a79842c9Skettenis {
353a79842c9Skettenis 	int i;
354a79842c9Skettenis 
355a79842c9Skettenis 	for (i = 1; i < cmd.argc; i++)
356a79842c9Skettenis 		printf("%s ", cmd.argv[i]);
357a79842c9Skettenis 	putchar('\n');
358a79842c9Skettenis 	return 0;
359a79842c9Skettenis }
360a79842c9Skettenis 
361a79842c9Skettenis static int
362a79842c9Skettenis Xls(void)
363a79842c9Skettenis {
364a79842c9Skettenis 	struct stat sb;
365a79842c9Skettenis 	const char *path;
366a79842c9Skettenis 	DIR *dir;
367a79842c9Skettenis 	struct dirent *dent;
368a79842c9Skettenis 	int dirfd, oldcwd;
369a79842c9Skettenis 
370a79842c9Skettenis 	path = disk_open(qualify(cmd.argv[1] ? cmd.argv[1] : "/."));
371a79842c9Skettenis 	if (path == NULL)
372a79842c9Skettenis 		return 0;
373a79842c9Skettenis 
374a79842c9Skettenis 	if (stat(path, &sb) < 0) {
375a79842c9Skettenis 		printf("stat(%s): %s\n", cmd.path, strerror(errno));
376a79842c9Skettenis 		goto out;
377a79842c9Skettenis 	}
378a79842c9Skettenis 
379a79842c9Skettenis 	if ((sb.st_mode & S_IFMT) != S_IFDIR)
380a79842c9Skettenis 		ls(path, &sb);
381a79842c9Skettenis 	else {
382a79842c9Skettenis 		oldcwd = open(".", O_RDONLY);
383a79842c9Skettenis 
384a79842c9Skettenis 		dirfd = open(path, O_RDONLY);
385a79842c9Skettenis 		if (dirfd < 0) {
386a79842c9Skettenis 			printf("opendir(%s): %s\n", cmd.path, strerror(errno));
387a79842c9Skettenis 			close(oldcwd);
388a79842c9Skettenis 			goto out;
389a79842c9Skettenis 		}
390a79842c9Skettenis 		if ((dir = fdopendir(dirfd)) < 0) {
391a79842c9Skettenis 			printf("opendir(%s): %s\n", cmd.path, strerror(errno));
392a79842c9Skettenis 			close(dirfd);
393a79842c9Skettenis 			close(oldcwd);
394a79842c9Skettenis 			goto out;
395a79842c9Skettenis 		}
396a79842c9Skettenis 		fchdir(dirfd);
397a79842c9Skettenis 		while ((dent = readdir(dir)) != NULL) {
398a79842c9Skettenis 			if (fstatat(dirfd, dent->d_name, &sb,
399a79842c9Skettenis 			    AT_SYMLINK_NOFOLLOW) < 0)
400a79842c9Skettenis 				printf("stat(%s): %s\n", dent->d_name,
401a79842c9Skettenis 				    strerror(errno));
402a79842c9Skettenis 			else
403a79842c9Skettenis 				ls(dent->d_name, &sb);
404a79842c9Skettenis 		}
405a79842c9Skettenis 		closedir(dir);
406a79842c9Skettenis 
407a79842c9Skettenis 		fchdir(oldcwd);
408a79842c9Skettenis 		close(oldcwd);
409a79842c9Skettenis 	}
410a79842c9Skettenis 
411a79842c9Skettenis out:
412a79842c9Skettenis 	disk_close();
413a79842c9Skettenis 	return 0;
414a79842c9Skettenis }
415a79842c9Skettenis 
416a79842c9Skettenis #define lsrwx(mode,s) \
417a79842c9Skettenis 	putchar ((mode) & S_IROTH? 'r' : '-'); \
418a79842c9Skettenis 	putchar ((mode) & S_IWOTH? 'w' : '-'); \
419a79842c9Skettenis 	putchar ((mode) & S_IXOTH? *(s): (s)[1]);
420a79842c9Skettenis 
421a79842c9Skettenis static void
422a79842c9Skettenis ls(const char *name, struct stat *sb)
423a79842c9Skettenis {
424a79842c9Skettenis 	putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]);
425a79842c9Skettenis 	lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-"));
426a79842c9Skettenis 	lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-"));
427a79842c9Skettenis 	lsrwx(sb->st_mode     , (sb->st_mode & S_ISTXT? "tT" : "x-"));
428a79842c9Skettenis 
429a79842c9Skettenis 	printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid,
430a79842c9Skettenis 	    (u_long)sb->st_size, name);
431a79842c9Skettenis }
432a79842c9Skettenis #undef lsrwx
433a79842c9Skettenis 
434a79842c9Skettenis int doboot = 1;
435a79842c9Skettenis 
436a79842c9Skettenis static int
437a79842c9Skettenis Xnop(void)
438a79842c9Skettenis {
439a79842c9Skettenis 	if (doboot) {
440a79842c9Skettenis 		doboot = 0;
441a79842c9Skettenis 		return (Xboot());
442a79842c9Skettenis 	}
443a79842c9Skettenis 
444a79842c9Skettenis 	return 0;
445a79842c9Skettenis }
446a79842c9Skettenis 
447a79842c9Skettenis static int
448a79842c9Skettenis Xboot(void)
449a79842c9Skettenis {
450a79842c9Skettenis 	if (cmd.argc > 1 && cmd.argv[1][0] != '-') {
451a79842c9Skettenis 		qualify((cmd.argv[1]? cmd.argv[1]: cmd.image));
452a79842c9Skettenis 		if (bootparse(2))
453a79842c9Skettenis 			return 0;
454a79842c9Skettenis 	} else {
455a79842c9Skettenis 		if (bootparse(1))
456a79842c9Skettenis 			return 0;
457a79842c9Skettenis 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
458a79842c9Skettenis 		    cmd.bootdev, cmd.image);
459a79842c9Skettenis 	}
460a79842c9Skettenis 
461a79842c9Skettenis 	return 1;
462a79842c9Skettenis }
463a79842c9Skettenis 
464a79842c9Skettenis /*
465a79842c9Skettenis  * Qualifies the path adding necessary dev
466a79842c9Skettenis  */
467a79842c9Skettenis 
468a79842c9Skettenis static char *
469a79842c9Skettenis qualify(char *name)
470a79842c9Skettenis {
471a79842c9Skettenis 	char *p;
472a79842c9Skettenis 
473a79842c9Skettenis 	for (p = name; *p; p++)
474a79842c9Skettenis 		if (*p == ':')
475a79842c9Skettenis 			break;
476a79842c9Skettenis 	if (*p == ':')
477a79842c9Skettenis 		strlcpy(cmd.path, name, sizeof(cmd.path));
478a79842c9Skettenis 	else
479a79842c9Skettenis 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
480a79842c9Skettenis 		    cmd.bootdev, name);
481a79842c9Skettenis 	return cmd.path;
482a79842c9Skettenis }
483a79842c9Skettenis 
484a79842c9Skettenis static int
485a79842c9Skettenis Xreboot(void)
486a79842c9Skettenis {
487a79842c9Skettenis 	printf("Rebooting...\n");
488a79842c9Skettenis 	reboot(0);
489a79842c9Skettenis 	return 0; /* just in case */
490a79842c9Skettenis }
491a79842c9Skettenis 
492a79842c9Skettenis int
493a79842c9Skettenis upgrade(void)
494a79842c9Skettenis {
495a79842c9Skettenis 	struct stat sb;
496a79842c9Skettenis 	const char *path;
497a79842c9Skettenis 	int ret = 0;
498a79842c9Skettenis 
499a79842c9Skettenis 	path = disk_open(qualify("/bsd.upgrade"));
500a79842c9Skettenis 	if (path == NULL)
501a79842c9Skettenis 		return 0;
502*57e232a5Smiod 	if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)) {
503a79842c9Skettenis 		ret = 1;
5043f0bb8e9Skn 		if ((sb.st_mode & S_IXUSR) == 0) {
5053f0bb8e9Skn 			printf("/bsd.upgrade is not u+x\n");
5063f0bb8e9Skn 			ret = 0;
5073f0bb8e9Skn 		}
508*57e232a5Smiod 	}
509a79842c9Skettenis 	disk_close();
510a79842c9Skettenis 
511a79842c9Skettenis 	return ret;
512a79842c9Skettenis }
513