541 lines · 14.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Convert integer string representation to an integer. * If an integer doesn't fit into specified type, -E is returned. * * Integer starts with optional sign. * kstrtou*() functions do not accept sign "-". * * Radix 0 means autodetection: leading "0x" implies radix 16, * leading "0" implies radix 8, otherwise radix is 10. * Autodetection hints work after optional sign, but not before. * * If -E is returned, result is not touched. */#include <linux/ctype.h>#include <linux/errno.h>#include <linux/export.h>#include <linux/kstrtox.h>#include <linux/math64.h>#include <linux/overflow.h>#include <linux/types.h>#include <linux/uaccess.h> #include "kstrtox.h" noinlineconst char *_parse_integer_fixup_radix(const char *s, unsigned int *base){	if (*base == 0) {		if (s[0] == '0') {			if (_tolower(s[1]) == 'x' && isxdigit(s[2]))				*base = 16;			else				*base = 8;		} else			*base = 10;	}	if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')		s += 2;	return s;} /** * _parse_integer_limit - Convert integer string representation to an integer * @s: Integer string representation * @base: Radix * @p: Where to store result * @max_chars: Maximum amount of characters to convert * @init: Initial value of the multiply-accumulate result * * Convert non-negative integer string representation in explicitly given * radix to an integer. If overflow occurs, value at @p is set to ULLONG_MAX. * * This function is the workhorse of other string conversion functions and it * is discouraged to use it explicitly. Consider kstrto*() family instead. * * Return: Number of characters consumed, maybe ORed with overflow bit */noinlineunsigned int _parse_integer_limit(const char *s, unsigned int base, unsigned long long *p,				  size_t max_chars, unsigned long long init){	unsigned int rv, overflow = 0;	unsigned long long res; 	res = init;	for (rv = 0; rv < max_chars; rv++, s++) {		unsigned int c = *s;		unsigned int lc = _tolower(c);		unsigned int val; 		if ('0' <= c && c <= '9')			val = c - '0';		else if ('a' <= lc && lc <= 'f')			val = lc - 'a' + 10;		else			break; 		if (val >= base)			break;		/*		 * Check for overflow only if we are within range of		 * it in the max base we support (16)		 */		if (unlikely(res & (~0ull << 60))) {			if (check_mul_overflow(res, base, &res) ||			    check_add_overflow(res, val, &res)) {				res = ULLONG_MAX;				overflow = KSTRTOX_OVERFLOW;			}		} else {			res = res * base + val;		}	}	*p = res;	return rv | overflow;} static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res){	unsigned long long _res;	unsigned int rv; 	s = _parse_integer_fixup_radix(s, &base);	rv = _parse_integer(s, base, &_res);	if (rv & KSTRTOX_OVERFLOW)		return -ERANGE;	if (rv == 0)		return -EINVAL;	s += rv;	if (*s == '\n')		s++;	if (*s)		return -EINVAL;	*res = _res;	return 0;} /** * kstrtoull - convert a string to an unsigned long long * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign, but not a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Preferred over simple_strtoull(). Return code must be checked. */noinlineint kstrtoull(const char *s, unsigned int base, unsigned long long *res){	if (s[0] == '+')		s++;	return _kstrtoull(s, base, res);}EXPORT_SYMBOL(kstrtoull); /** * kstrtoll - convert a string to a long long * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign or a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Preferred over simple_strtoll(). Return code must be checked. */noinlineint kstrtoll(const char *s, unsigned int base, long long *res){	unsigned long long tmp;	int rv; 	if (s[0] == '-') {		rv = _kstrtoull(s + 1, base, &tmp);		if (rv < 0)			return rv;		if ((long long)-tmp > 0)			return -ERANGE;		*res = -tmp;	} else {		rv = kstrtoull(s, base, &tmp);		if (rv < 0)			return rv;		if ((long long)tmp < 0)			return -ERANGE;		*res = tmp;	}	return 0;}EXPORT_SYMBOL(kstrtoll); /* Internal, do not use. */int _kstrtoul(const char *s, unsigned int base, unsigned long *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (unsigned long)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(_kstrtoul); /* Internal, do not use. */int _kstrtol(const char *s, unsigned int base, long *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (long)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(_kstrtol); /** * kstrtouint - convert a string to an unsigned int * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign, but not a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Preferred over simple_strtoul(). Return code must be checked. */noinlineint kstrtouint(const char *s, unsigned int base, unsigned int *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (unsigned int)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtouint); /** * kstrtoint - convert a string to an int * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign or a minus sign. * @base: The number base to use. The maximum supported base is 16. If base is *  given as 0, then the base of the string is automatically detected with the *  conventional semantics - If it begins with 0x the number will be parsed as a *  hexadecimal (case insensitive), if it otherwise begins with 0, it will be *  parsed as an octal number. Otherwise it will be parsed as a decimal. * @res: Where to write the result of the conversion on success. * * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. * Preferred over simple_strtol(). Return code must be checked. */noinlineint kstrtoint(const char *s, unsigned int base, int *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (int)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtoint); noinlineint kstrtou16(const char *s, unsigned int base, u16 *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (u16)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtou16); noinlineint kstrtos16(const char *s, unsigned int base, s16 *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (s16)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtos16); noinlineint kstrtou8(const char *s, unsigned int base, u8 *res){	unsigned long long tmp;	int rv; 	rv = kstrtoull(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (u8)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtou8); noinlineint kstrtos8(const char *s, unsigned int base, s8 *res){	long long tmp;	int rv; 	rv = kstrtoll(s, base, &tmp);	if (rv < 0)		return rv;	if (tmp != (s8)tmp)		return -ERANGE;	*res = tmp;	return 0;}EXPORT_SYMBOL(kstrtos8); /** * kstrtobool - convert common user inputs into boolean values * @s: input string * @res: result * * This routine returns 0 iff the first character is one of 'EeYyTt1DdNnFf0', * or [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL.  Value * pointed to by res is updated upon finding a match. */noinlineint kstrtobool(const char *s, bool *res){	if (!s)		return -EINVAL; 	switch (s[0]) {	case 'e':	case 'E':	case 'y':	case 'Y':	case 't':	case 'T':	case '1':		*res = true;		return 0;	case 'd':	case 'D':	case 'n':	case 'N':	case 'f':	case 'F':	case '0':		*res = false;		return 0;	case 'o':	case 'O':		switch (s[1]) {		case 'n':		case 'N':			*res = true;			return 0;		case 'f':		case 'F':			*res = false;			return 0;		default:			break;		}		break;	default:		break;	} 	return -EINVAL;}EXPORT_SYMBOL(kstrtobool); static int _kstrtoudec64(const char *s, unsigned int scale, u64 *res){	unsigned int rv_int, rv_frac;	u64 _res = 0; 	rv_int = _parse_integer(s, 10, &_res);	if (rv_int & KSTRTOX_OVERFLOW)		return -ERANGE;	s += rv_int; 	if (*s == '.')		s++; /* skip decimal point */ 	rv_frac = _parse_integer(s, 10, &_res, scale, _res);	if (rv_frac & KSTRTOX_OVERFLOW)		return -ERANGE;	s += rv_frac; 	/*	 * Check input beyond rv_int and rv_frac to cover cases like ".5" with	 * scale 0, which is considered a valid input, being parsed as 0.	 */	if (!rv_int && !rv_frac && !isdigit(*s))		return -EINVAL; 	while (isdigit(*s)) /* truncate digits */		s++; 	if (*s == '\n')		s++;	if (*s)		return -EINVAL; 	if (_res && ((scale - rv_frac) > 19 /* log10(2^64) = 19.26 */ ||		     check_mul_overflow(_res, int_pow(10, scale - rv_frac), &_res)))		return -ERANGE; 	*res = _res;	return 0;} /** * kstrtoudec64() - Convert a string to an unsigned 64-bit scaled decimal value. * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign, but not a minus sign. * @scale: The number of digits to the right of the decimal point. * @res: Where to write the result of the conversion on success. * * For example, a scale of 3 with input "123.45" results in 123450. Note that * trailing zeros in the fractional part input to match the scale are not * required. Also, digits beyond the specified scale are ignored. * * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error. */noinlineint kstrtoudec64(const char *s, unsigned int scale, u64 *res){	if (s[0] == '+')		s++;	return _kstrtoudec64(s, scale, res);}EXPORT_SYMBOL(kstrtoudec64); /** * kstrtodec64() - Convert a string to a signed 64-bit scaled decimal value. * @s: The start of the string. The string must be null-terminated, and may also *  include a single newline before its terminating null. The first character *  may also be a plus sign or a minus sign. * @scale: The number of digits to the right of the decimal point. * @res: Where to write the result of the conversion on success. * * For example, a scale of 4 with input "-3.141592" results in -31415. Note * that digits beyond the specified scale are ignored. Also, trailing zeros in * the fractional part input to match the scale are not required. * * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error. */noinlineint kstrtodec64(const char *s, unsigned int scale, s64 *res){	u64 tmp;	int rv; 	if (s[0] == '-') {		rv = _kstrtoudec64(s + 1, scale, &tmp);		if (rv < 0)			return rv;		if ((s64)-tmp > 0)			return -ERANGE;		*res = -tmp;	} else {		rv = kstrtoudec64(s, scale, &tmp);		if (rv < 0)			return rv;		if ((s64)tmp < 0)			return -ERANGE;		*res = tmp;	}	return 0;}EXPORT_SYMBOL(kstrtodec64); 

Lines 1–500 of 541.