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