diff options
Diffstat (limited to 'sys/arch/octeon/stand/rdboot/cmd.c')
-rw-r--r-- | sys/arch/octeon/stand/rdboot/cmd.c | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/sys/arch/octeon/stand/rdboot/cmd.c b/sys/arch/octeon/stand/rdboot/cmd.c new file mode 100644 index 00000000000..85c8a28e238 --- /dev/null +++ b/sys/arch/octeon/stand/rdboot/cmd.c @@ -0,0 +1,503 @@ +/* $OpenBSD: cmd.c,v 1.1 2019/07/17 14:36:32 visa Exp $ */ + +/* + * Copyright (c) 1997-1999 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/select.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "cmd.h" +#include "disk.h" + +static int Xboot(void); +static int Xecho(void); +static int Xhelp(void); +static int Xls(void); +static int Xnop(void); +static int Xreboot(void); +#ifdef MACHINE_CMD +static int Xmachine(void); +extern const struct cmd_table MACHINE_CMD[]; +#endif +extern int Xset(void); + +#ifdef CHECK_SKIP_CONF +extern int CHECK_SKIP_CONF(void); +#endif + +extern const struct cmd_table cmd_set[]; +const struct cmd_table cmd_table[] = { + {"#", CMDT_CMD, Xnop}, /* XXX must be first */ + {"boot", CMDT_CMD, Xboot}, + {"echo", CMDT_CMD, Xecho}, + {"help", CMDT_CMD, Xhelp}, + {"ls", CMDT_CMD, Xls}, +#ifdef MACHINE_CMD + {"machine",CMDT_MDC, Xmachine}, +#endif + {"reboot", CMDT_CMD, Xreboot}, + {"set", CMDT_SET, Xset}, + {NULL, 0}, +}; + +static void ls(const char *, struct stat *); +static int readline(char *, size_t, int); +char *nextword(char *); +static char *whatcmd(const struct cmd_table **ct, char *); +static char *qualify(char *); + +char cmd_buf[CMD_BUFF_SIZE]; + +int +getcmd(void) +{ + cmd.cmd = NULL; + + if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout)) + cmd.cmd = cmd_table; + + return docmd(); +} + +int +read_conf(void) +{ + struct stat sb; + const char *path; + int fd, rc = 0; + +#ifdef CHECK_SKIP_CONF + if (CHECK_SKIP_CONF()) { + printf("boot.conf processing skipped at operator request\n"); + cmd.timeout = 0; + return -1; /* Pretend file wasn't found */ + } +#endif + + path = disk_open(qualify(cmd.conf)); + if (path == NULL) { + fprintf(stderr, "cannot open device for reading %s: %s\n", + cmd.conf, strerror(errno)); + return -1; + } + if ((fd = open(path, O_RDONLY)) == -1) { + if (errno != ENOENT && errno != ENXIO) { + fprintf(stderr, "%s: open(%s): %s\n", __func__, + cmd.path, strerror(errno)); + rc = 0; + } else + rc = -1; + goto out; + } + + (void) fstat(fd, &sb); + if (sb.st_uid || (sb.st_mode & 2)) { + fprintf(stderr, "non-secure %s, will not proceed\n", cmd.path); + rc = -1; + goto out; + } + + do { + char *p = cmd_buf; + + cmd.cmd = NULL; + do { + rc = read(fd, p, 1); + } while (rc > 0 && *p++ != '\n' && + (p-cmd_buf) < sizeof(cmd_buf)); + + if (rc < 0) { /* Error from read() */ + fprintf(stderr, "%s: %s\n", cmd.path, strerror(errno)); + break; + } + + if (rc == 0) { /* eof from read() */ + if (p != cmd_buf) { /* Line w/o trailing \n */ + *p = '\0'; + rc = docmd(); + break; + } + } else { /* rc > 0, read a char */ + p--; /* Get back to last character */ + + if (*p != '\n') { /* Line was too long */ + fprintf(stderr, "%s: line too long\n", + cmd.path); + + /* Don't want to run the truncated command */ + rc = -1; + } + *p = '\0'; + } + } while (rc > 0 && !(rc = docmd())); + +out: + if (fd != -1) + close(fd); + disk_close(); + return rc; +} + +int +docmd(void) +{ + char *p = NULL; + const struct cmd_table *ct = cmd_table, *cs; + + cmd.argc = 1; + if (cmd.cmd == NULL) { + + /* command */ + for (p = cmd_buf; *p == ' ' || *p == '\t'; p++) + ; + if (*p == '#' || *p == '\0') { /* comment or empty string */ +#ifdef DEBUG + printf("rem\n"); +#endif + return 0; + } + ct = cmd_table; + cs = NULL; + cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */ + p = whatcmd(&ct, p); + if (ct == NULL) { + cmd.argc++; + ct = cmd_table; + } else if (ct->cmd_type == CMDT_SET && p != NULL) { + cs = cmd_set; +#ifdef MACHINE_CMD + } else if (ct->cmd_type == CMDT_MDC && p != NULL) { + cs = MACHINE_CMD; +#endif + } + + if (cs != NULL) { + p = whatcmd(&cs, p); + if (cs == NULL) { + printf("%s: syntax error\n", ct->cmd_name); + return 0; + } + ct = cs; + } + cmd.cmd = ct; + } + + cmd.argv[0] = ct->cmd_name; + while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) { + cmd.argv[cmd.argc++] = p; + p = nextword(p); + } + cmd.argv[cmd.argc] = NULL; + + return (*cmd.cmd->cmd_exec)(); +} + +static char * +whatcmd(const struct cmd_table **ct, char *p) +{ + char *q; + int l; + + q = nextword(p); + + for (l = 0; p[l]; l++) + ; + + while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l)) + (*ct)++; + + if ((*ct)->cmd_name == NULL) + *ct = NULL; + + return q; +} + +static int +readline(char *buf, size_t n, int to) +{ + struct termios saved_tio, tio; + struct timeval tv; + fd_set fdset; + int timed_out = 0; +#ifdef DEBUG + extern int debug; +#endif + + /* Only do timeout if greater than 0 */ + if (to > 0) { + /* Switch to non-canonical mode for timeout detection. */ + tcgetattr(STDIN_FILENO, &saved_tio); + tio = saved_tio; + tio.c_lflag &= ~(ECHO | ICANON); + tcsetattr(STDIN_FILENO, TCSANOW, &tio); + + FD_ZERO(&fdset); + FD_SET(STDIN_FILENO, &fdset); + tv.tv_sec = to; + tv.tv_usec = 0; + if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, &tv) == 0) + timed_out = 1; + + /* Restore canonical mode. */ + tcsetattr(STDIN_FILENO, TCSANOW, &saved_tio); + + if (timed_out) { + strlcpy(buf, "boot", 5); + putchar('\n'); + return strlen(buf); + } + } + + /* User has typed something. Turn off timeouts. */ + cmd.timeout = 0; + + if (fgets(buf, n, stdin) == NULL) + return 0; + + /* Strip trailing newline. */ + strtok(buf, "\n"); + + return strlen(buf); +} + +/* + * Search for spaces/tabs after the current word. If found, \0 the + * first one. Then pass a pointer to the first character of the + * next word, or NULL if there is no next word. + */ +char * +nextword(char *p) +{ + /* skip blanks */ + while (*p && *p != '\t' && *p != ' ') + p++; + if (*p) { + *p++ = '\0'; + while (*p == '\t' || *p == ' ') + p++; + } + if (*p == '\0') + p = NULL; + return p; +} + +static void +print_help(const struct cmd_table *ct) +{ + for (; ct->cmd_name != NULL; ct++) + printf(" %s", ct->cmd_name); + putchar('\n'); +} + +static int +Xhelp(void) +{ + printf("commands:"); + print_help(cmd_table); +#ifdef MACHINE_CMD + return Xmachine(); +#else + return 0; +#endif +} + +#ifdef MACHINE_CMD +static int +Xmachine(void) +{ + printf("machine:"); + print_help(MACHINE_CMD); + return 0; +} +#endif + +static int +Xecho(void) +{ + int i; + + for (i = 1; i < cmd.argc; i++) + printf("%s ", cmd.argv[i]); + putchar('\n'); + return 0; +} + +static int +Xls(void) +{ + struct stat sb; + const char *path; + DIR *dir; + struct dirent *dent; + int dirfd, oldcwd; + + path = disk_open(qualify(cmd.argv[1] ? cmd.argv[1] : "/.")); + if (path == NULL) + return 0; + + if (stat(path, &sb) < 0) { + printf("stat(%s): %s\n", cmd.path, strerror(errno)); + goto out; + } + + if ((sb.st_mode & S_IFMT) != S_IFDIR) + ls(path, &sb); + else { + oldcwd = open(".", O_RDONLY); + + dirfd = open(path, O_RDONLY); + if (dirfd < 0) { + printf("opendir(%s): %s\n", cmd.path, strerror(errno)); + close(oldcwd); + goto out; + } + if ((dir = fdopendir(dirfd)) < 0) { + printf("opendir(%s): %s\n", cmd.path, strerror(errno)); + close(dirfd); + close(oldcwd); + goto out; + } + fchdir(dirfd); + while ((dent = readdir(dir)) != NULL) { + if (fstatat(dirfd, dent->d_name, &sb, + AT_SYMLINK_NOFOLLOW) < 0) + printf("stat(%s): %s\n", dent->d_name, + strerror(errno)); + else + ls(dent->d_name, &sb); + } + closedir(dir); + + fchdir(oldcwd); + } + +out: + disk_close(); + return 0; +} + +#define lsrwx(mode,s) \ + putchar ((mode) & S_IROTH? 'r' : '-'); \ + putchar ((mode) & S_IWOTH? 'w' : '-'); \ + putchar ((mode) & S_IXOTH? *(s): (s)[1]); + +static void +ls(const char *name, struct stat *sb) +{ + putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]); + lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-")); + lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-")); + lsrwx(sb->st_mode , (sb->st_mode & S_ISTXT? "tT" : "x-")); + + printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid, + (u_long)sb->st_size, name); +} +#undef lsrwx + +int doboot = 1; + +static int +Xnop(void) +{ + if (doboot) { + doboot = 0; + return (Xboot()); + } + + return 0; +} + +static int +Xboot(void) +{ + if (cmd.argc > 1 && cmd.argv[1][0] != '-') { + qualify((cmd.argv[1]? cmd.argv[1]: cmd.image)); + if (bootparse(2)) + return 0; + } else { + if (bootparse(1)) + return 0; + snprintf(cmd.path, sizeof cmd.path, "%s:%s", + cmd.bootdev, cmd.image); + } + + return 1; +} + +/* + * Qualifies the path adding necessary dev + */ + +static char * +qualify(char *name) +{ + char *p; + + for (p = name; *p; p++) + if (*p == ':') + break; + if (*p == ':') + strlcpy(cmd.path, name, sizeof(cmd.path)); + else + snprintf(cmd.path, sizeof cmd.path, "%s:%s", + cmd.bootdev, name); + return cmd.path; +} + +static int +Xreboot(void) +{ + printf("Rebooting...\n"); + reboot(0); + return 0; /* just in case */ +} + +int +upgrade(void) +{ + struct stat sb; + const char *path; + int ret = 0; + + path = disk_open(qualify("/bsd.upgrade")); + if (path == NULL) + return 0; + if (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)) + ret = 1; + disk_close(); + + return ret; +} |