Edit

IABSD.fr/src/sbin/fdisk/misc.c

Branch :

  • Show log

    Commit

  • Author : krw
    Date : 2022-07-10 20:34:31
    Hash : c5fb5a34
    Message : Add some anti-feline input protection by refusing to process input of excessive length. Make 'args' parameter to Xfuncs const char * and do the multiple argument parsing in Xswap() and Xflag() on a local copy.

  • sbin/fdisk/misc.c
  • /*	$OpenBSD: misc.c,v 1.88 2022/07/10 20:34:31 krw Exp $	*/
    
    /*
     * Copyright (c) 1997 Tobias Weingartner
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <sys/types.h>
    #include <sys/disklabel.h>
    
    #include <ctype.h>
    #include <err.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include "part.h"
    #include "disk.h"
    #include "misc.h"
    
    const struct unit_type	unit_types[] = {
    	{ "b"	, 1LL				, "Bytes"	},
    	{ " "	, 0LL				, "Sectors"	},
    	{ "K"	, 1024LL			, "Kilobytes"	},
    	{ "M"	, 1024LL * 1024			, "Megabytes"	},
    	{ "G"	, 1024LL * 1024 *1024		, "Gigabytes"	},
    	{ "T"	, 1024LL * 1024 * 1024 * 1024	, "Terabytes"	},
    };
    #define	SECTORS		1
    
    double
    units_size(const char *units, const uint64_t sectors,
        const struct unit_type **ut)
    {
    	double			size;
    	unsigned int		i;
    
    	*ut = &unit_types[SECTORS];
    	size = sectors;
    
    	for (i = 0; i < nitems(unit_types); i++) {
    		if (strncasecmp(unit_types[i].ut_abbr, units, 1) == 0)
    			*ut = &unit_types[i];
    	}
    
    	if ((*ut)->ut_conversion == 0)
    		return size;
    	else
    		return (size * dl.d_secsize) / (*ut)->ut_conversion;
    }
    
    void
    string_from_line(char *buf, const size_t buflen, const int trim)
    {
    	static char		*line;
    	static size_t		 sz;
    	ssize_t			 len;
    	size_t			 n;
    	unsigned int		 i;
    
    	len = getline(&line, &sz, stdin);
    	if (len == -1)
    		errx(1, "eof");
    
    	switch (trim) {
    	case UNTRIMMED:
    		line[strcspn(line, "\n")] = '\0';
    		n = strlcpy(buf, line, buflen);
    		break;
    	case TRIMMED:
    		for (i = strlen(line); i > 0; i--) {
    			if (isspace((unsigned char)line[i - 1]) == 0)
    				break;
    			line[i - 1] = '\0';
    		}
    		n = strlcpy(buf, line + strspn(line, WHITESPACE), buflen);
    		break;
    	}
    
    	if (n >= buflen) {
    		printf("input too long\n");
    		memset(buf, 0, buflen);
    	}
    }
    
    int
    ask_yn(const char *str)
    {
    	int			ch, first;
    	extern int		y_flag;
    
    	if (y_flag)
    		return 1;
    
    	printf("%s [n] ", str);
    	fflush(stdout);
    
    	first = ch = getchar();
    	while (ch != '\n' && ch != EOF)
    		ch = getchar();
    
    	if (ch == EOF || first == EOF)
    		errx(1, "eof");
    
    	return first == 'y' || first == 'Y';
    }
    
    /*
     * adapted from sbin/disklabel/editor.c
     */
    uint64_t
    getuint64(const char *prompt, uint64_t oval, const uint64_t minval,
        const uint64_t maxval)
    {
    	char			buf[BUFSIZ], *endptr, *p, operator = '\0';
    	const int		secsize = dl.d_secsize;
    	size_t			n;
    	int64_t			mult = 1;
    	double			d, d2;
    	int			rslt, secpercyl, saveerr;
    	char			unit;
    
    	if (oval > maxval)
    		oval = maxval;
    	if (oval < minval)
    		oval = minval;
    
    	secpercyl = disk.dk_sectors * disk.dk_heads;
    
    	do {
    		printf("%s [%llu - %llu]: [%llu] ", prompt, minval, maxval,
    		    oval);
    		string_from_line(buf, sizeof(buf), TRIMMED);
    
    		if (buf[0] == '\0') {
    			rslt = snprintf(buf, sizeof(buf), "%llu", oval);
    			if (rslt < 0 || rslt >= sizeof(buf))
    				errx(1, "default value too long");
    		} else if (buf[0] == '*' && buf[1] == '\0') {
    			return maxval;
    		}
    
    		/* deal with units */
    		n = strlen(buf);
    		switch (tolower((unsigned char)buf[n-1])) {
    		case 'c':
    			unit = 'c';
    			mult = secpercyl;
    			buf[--n] = '\0';
    			break;
    		case 'b':
    			unit = 'b';
    			mult = -(int64_t)secsize;
    			buf[--n] = '\0';
    			break;
    		case 's':
    			unit = 's';
    			mult = 1;
    			buf[--n] = '\0';
    			break;
    		case 'k':
    			unit = 'k';
    			if (secsize > 1024)
    				mult = -(int64_t)secsize / 1024LL;
    			else
    				mult = 1024LL / secsize;
    			buf[--n] = '\0';
    			break;
    		case 'm':
    			unit = 'm';
    			mult = (1024LL * 1024) / secsize;
    			buf[--n] = '\0';
    			break;
    		case 'g':
    			unit = 'g';
    			mult = (1024LL * 1024 * 1024) / secsize;
    			buf[--n] = '\0';
    			break;
    		case 't':
    			unit = 't';
    			mult = (1024LL * 1024 * 1024 * 1024) / secsize;
    			buf[--n] = '\0';
    			break;
    		default:
    			unit = ' ';
    			mult = 1;
    			break;
    		}
    
    		/* deal with the operator */
    		p = &buf[0];
    		if (*p == '+' || *p == '-')
    			operator = *p++;
    		else
    			operator = ' ';
    
    		endptr = p;
    		errno = 0;
    		d = strtod(p, &endptr);
    		saveerr = errno;
    		d2 = d;
    		if (mult > 0)
    			d *= mult;
    		else {
    			d /= (-mult);
    			d2 = d;
    		}
    
    		/* Apply the operator */
    		if (operator == '+')
    			d = oval + d;
    		else if (operator == '-') {
    			d = oval - d;
    			d2 = d;
    		}
    
    		if (saveerr == ERANGE || d > maxval || d < minval || d < d2) {
    			printf("%s is out of range: %c%s%c\n", prompt, operator,
    			    p, unit);
    		} else if (*endptr != '\0') {
    			printf("%s is invalid: %c%s%c\n", prompt, operator,
    			    p, unit);
    		} else {
    			break;
    		}
    	} while (1);
    
    	return (uint64_t)d;
    }
    
    int
    hex_octet(char *buf)
    {
    	char			*cp;
    	long			 num;
    
    	cp = buf;
    	num = strtol(buf, &cp, 16);
    
    	if (cp == buf || *cp != '\0')
    		return -1;
    
    	if (num < 0 || num > 0xff)
    		return -1;
    
    	return num;
    }