Edit

IABSD.fr/src/sys/stand/boot/cmd.c

Branch :

  • Show log

    Commit

  • Author : deraadt
    Date : 2019-12-02 01:38:06
    Hash : 1f267e12
    Message : For 32 bit systems, cast the long long used by strtoll() to unsigned long and then a void * for calling the hexdump() operator with bluhm

  • sys/stand/boot/cmd.c
  • /*	$OpenBSD: cmd.c,v 1.67 2019/12/02 01:38:06 deraadt 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 <libsa.h>
    #include <lib/libkern/funcs.h>
    
    #include "cmd.h"
    
    #define CTRL(c)	((c)&0x1f)
    
    static int Xboot(void);
    static int Xecho(void);
    static int Xhelp(void);
    static int Xhexdump(void);
    static int Xls(void);
    static int Xnop(void);
    static int Xreboot(void);
    static int Xstty(void);
    static int Xtime(void);
    #ifdef MACHINE_CMD
    static int Xmachine(void);
    extern const struct cmd_table MACHINE_CMD[];
    #endif
    extern int Xset(void);
    extern int Xenv(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},
    	{"env",    CMDT_CMD, Xenv},
    	{"help",   CMDT_CMD, Xhelp},
    	{"hexdump",CMDT_CMD, Xhexdump},
    	{"ls",     CMDT_CMD, Xls},
    #ifdef MACHINE_CMD
    	{"machine",CMDT_MDC, Xmachine},
    #endif
    	{"reboot", CMDT_CMD, Xreboot},
    	{"set",    CMDT_SET, Xset},
    	{"stty",   CMDT_CMD, Xstty},
    	{"time",   CMDT_CMD, Xtime},
    	{NULL, 0},
    };
    
    static void ls(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)
    {
    #ifndef INSECURE
    	struct stat sb;
    #endif
    	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
    
    	if ((fd = open(qualify(cmd.conf), 0)) < 0) {
    		if (errno != ENOENT && errno != ENXIO) {
    			printf("open(%s): %s\n", cmd.path, strerror(errno));
    			return 0;
    		}
    		return -1;
    	}
    
    #ifndef INSECURE
    	(void) fstat(fd, &sb);
    	if (sb.st_uid || (sb.st_mode & 2)) {
    		printf("non-secure %s, will not proceed\n", cmd.path);
    		close(fd);
    		return -1;
    	}
    #endif
    
    	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() */
    			printf("%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 */
    				printf("%s: line too long\n", cmd.path);
    
    				/* Don't want to run the truncated command */
    				rc = -1;
    			}
    			*p = '\0';
    		}
    	} while (rc > 0 && !(rc = docmd()));
    
    	close(fd);
    	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)
    {
    #ifdef DEBUG
    	extern int debug;
    #endif
    	char *p = buf, ch;
    
    	/* Only do timeout if greater than 0 */
    	if (to > 0) {
    		u_long i = 0;
    		time_t tt = getsecs() + to;
    #ifdef DEBUG
    		if (debug > 2)
    			printf ("readline: timeout(%d) at %u\n", to, tt);
    #endif
    		/* check for timeout expiration less often
    		   (for some very constrained archs) */
    		while (!cnischar())
    			if (!(i++ % 1000) && (getsecs() >= tt))
    				break;
    
    		if (!cnischar()) {
    			strlcpy(buf, "boot", 5);
    			putchar('\n');
    			return strlen(buf);
    		}
    	} else
    		while (!cnischar())
    			;
    
    	/* User has typed something.  Turn off timeouts. */
    	cmd.timeout = 0;
    
    	while (1) {
    		switch ((ch = getchar())) {
    		case CTRL('u'):
    			while (p > buf) {
    				putchar('\177');
    				p--;
    			}
    			continue;
    		case '\n':
    		case '\r':
    			*p = '\0';
    			break;
    		case '\b':
    		case '\177':
    			if (p > buf) {
    				putchar('\177');
    				p--;
    			}
    			continue;
    		default:
    			if (ch >= ' ' && ch < '\177') {
    				if (p - buf < n-1)
    					*p++ = ch;
    				else {
    					putchar('\007');
    					putchar('\177');
    				}
    			}
    			continue;
    		}
    		break;
    	}
    
    	return p - 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
    }
    
    static int
    Xhexdump(void)
    {
    	long long val[2];
    	char *ep;
    	int i;
    
    	if (cmd.argc != 3) {
    		printf("hexdump addr size\n");
    		return 0;
    	}
    
    	for (i = 1; i < cmd.argc; i++) {
    		val[i-1] = strtoll(cmd.argv[i], &ep, 0);
    		if (cmd.argv[i][0] == '\0' || *ep != '\0') {
    			printf("bad '%c' in \"%s\"\n", *ep, cmd.argv[i]);
    			return 0;
    		}
    	}
    	hexdump((void *)(unsigned long)val[0], val[1]);
    	return 0;
    }
    
    #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
    Xstty(void)
    {
    	int sp;
    	char *cp;
    	dev_t dev;
    
    	if (cmd.argc == 1) {
    		printf("%s speed is %d\n", ttyname(0), cnspeed(0, -1));
    		return 0;
    	}
    	dev = ttydev(cmd.argv[1]);
    	if (dev == NODEV) {
    		printf("%s not a console device\n", cmd.argv[1]);
    		return 0;
    	}
    
    	if (cmd.argc == 2)
    		printf("%s speed is %d\n", cmd.argv[1],
    		    cnspeed(dev, -1));
    	else {
    		sp = 0;
    		for (cp = cmd.argv[2]; isdigit(*cp); cp++)
    			sp = sp * 10 + (*cp - '0');
    		cnspeed(dev, sp);
    	}
    	return 0;
    }
    
    static int
    Xtime(void)
    {
    	time_t tt = getsecs();
    
    	if (cmd.argc == 1)
    		printf(ctime(&tt));
    
    	return 0;
    }
    
    static int
    Xls(void)
    {
    	struct stat sb;
    	char *p;
    	int fd;
    
    	if (stat(qualify((cmd.argv[1]? cmd.argv[1]: "/.")), &sb) < 0) {
    		printf("stat(%s): %s\n", cmd.path, strerror(errno));
    		return 0;
    	}
    
    	if ((sb.st_mode & S_IFMT) != S_IFDIR)
    		ls(cmd.path, &sb);
    	else {
    		if ((fd = opendir(cmd.path)) < 0) {
    			printf("opendir(%s): %s\n", cmd.path,
    			    strerror(errno));
    			return 0;
    		}
    
    		/* no strlen in lib !!! */
    		for (p = cmd.path; *p; p++)
    			;
    		*p++ = '/';
    		*p = '\0';
    
    		while (readdir(fd, p) >= 0) {
    			if (stat(cmd.path, &sb) < 0)
    				printf("stat(%s): %s\n", cmd.path,
    				    strerror(errno));
    			else
    				ls(p, &sb);
    		}
    		closedir (fd);
    	}
    	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(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");
    	exit();
    	return 0; /* just in case */
    }
    
    int
    upgrade(void)
    {
    	struct stat sb;
    
    	if (stat(qualify(("/bsd.upgrade")), &sb) < 0)
    		return 0;
    	if ((sb.st_mode & S_IXUSR) == 0) {
    		printf("/bsd.upgrade is not u+x\n");
    		return 0;
    	}
    	return 1;
    }