Skip to contentSkip to conversation

Add parse_integer() (replacement for simple_strto*())

PATCH In review Alexey Dobriyan 2 participants 6 messages Apr 9, 2015 – Apr 11, 2015

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Add parse_integer() (replacement for simple_strto*())

kstrto*() and kstrto*_from_user() family of functions were added help with parsing one integer written as string to proc/sysfs/debugfs files and pass it elsewhere. But they have a limitation: string passed must end with \0 or \n\0. There are enough places where kstrto*() functions can't be used because of this limitation. Trivial example:
parse "%u.%u".

Currently the only way to parse everything is simple_strto*() family of functions. But they are suboptimal:
* they do not detect overflow,
* there are only 2(4) of them -- long and "long long" version. This leads to silent truncation in the most simple case:

	val = strtoul(s, NULL, 0);

* half of the people think that "char **endp" argument is necessary and add unnecessary variable.

OpenBSD people, fed up with how complex correct integer parsing is, added strtonum(3) to fixup for deficiencies of libc-style integer parsing:
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/strtonum.3?query=strtonum&arch=i386

It'd be OK to copy that but it relies on "errno" and fixed strings as error-reporting channel which I think is not OK for kernel. strtonum() also doesn't report number of characted consumed.

What to do?

Enter parse_integer().

	int parse_integer(const char *s, unsigned int base, T *val);

Rationale:

* parse_integer() is exactly 1 (one) interface not 2 or many, one for each type.
* parse_integer() reports -E errors reliably in a canonical kernel way:

	rv = parse_integer(str, 10, &val);
	if (rv < 0)
		return rv;

* parse_integer() writes result only if there were no errors, at least one digit was consumed.
* parse_integer doesn't mix error reporting channel and value channel, it does mix error and number-of-character-consumed channel, though.

* parse_integer() reports number of characters consumed, makes parsing multiple values easy:

	rv = parse_integer(str, 0, &val1);
	if (rv < 0)
		return rv;
	s += rv;
	if (s != '.')
		return -EINVAL;
	rv = parse_integer(str, 0, &val2);
	if (rv < 0)
		return rv;
	if (str[rv] != '\0')
		return -EINVAL;

There are several deficiencies in parse_integer() compared to strto*():
* can't be used in initializers:

	const T x = strtoul();

* can't be used with bitfields,
* can't be used in experessions:

	x = strtol() * 1024;
	x = y = strtol() * 1024;
	x += strtol();

In defense of parse_integer() all I can say, is that using strtol() in expression or initializer promotes no error checking and thus probably should not be encouraged in C, language with no built-in error checking anyway.

The amount of "x = y = strtol()" expressions in kernel is very small. The amount of direct usage in expression is not small, but can be counted as an acceptable loss.

---

 include/linux/kernel.h |   72 +++++++++++++++++++
 lib/Makefile           |    1 
 lib/kstrtox.c          |   27 +------
 lib/parse-integer.c    |  180 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 257 insertions(+), 23 deletions(-)
include/linux/kernel.h +72 -0
@@ -251,6 +251,78 @@ void do_exit(long error_code)
 void complete_and_exit(struct completion *, long)
 	__noreturn;
 
+/*
+ * int parse_integer(const char *s, unsigned int base, T *val);
+ *
+ * Convert integer string representation to an integer.
+ * If an integer doesn't fit into specified type, -E is returned.
+ *
+ * Conversion to signed integer accepts sign "-".
+ * Conversion to an unsigned integer doesn't 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.
+ *
+ * "T = char" case is not supported because -f{un,}signed-char can silently
+ * change range of accepted values.
+ */
+#define parse_integer(s, base, val)	\
+({					\
+	const char *_s = (s);		\
+	unsigned int _base = (base);	\
+	typeof(val) _val = (val);	\
+					\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), signed char *),	\
+	_parse_integer_sc(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), unsigned char *),	\
+	_parse_integer_uc(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), short *),		\
+	_parse_integer_s(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), unsigned short *),	\
+	_parse_integer_us(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), int *),		\
+	_parse_integer_i(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), unsigned int *),	\
+	_parse_integer_u(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), long *) && BITS_PER_LONG == 32,\
+	_parse_integer_i(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), long *) && BITS_PER_LONG == 64,\
+	_parse_integer_ll(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), unsigned long *) && BITS_PER_LONG == 32,\
+	_parse_integer_u(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), unsigned long *) && BITS_PER_LONG == 64,\
+	_parse_integer_ull(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), long long *),	\
+	_parse_integer_ll(_s, _base, (void *)_val),			\
+	__builtin_choose_expr(						\
+	__builtin_types_compatible_p(typeof(_val), unsigned long long *),\
+	_parse_integer_ull(_s, _base, (void *)_val),			\
+	_parse_integer_link_time_error()))))))))))));	\
+})
+int _parse_integer_sc(const char *s, unsigned int base, signed char *val);
+int _parse_integer_uc(const char *s, unsigned int base, unsigned char *val);
+int _parse_integer_s(const char *s, unsigned int base, short *val);
+int _parse_integer_us(const char *s, unsigned int base, unsigned short *val);
+int _parse_integer_i(const char *s, unsigned int base, int *val);
+int _parse_integer_u(const char *s, unsigned int base, unsigned int *val);
+int _parse_integer_ll(const char *s, unsigned int base, long long *val);
+int _parse_integer_ull(const char *s, unsigned int base, unsigned long long *val);
+void _parse_integer_link_time_error(void);
+
 /* Internal, do not use. */
 int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res);
 int __must_check _kstrtol(const char *s, unsigned int base, long *res);
lib/Makefile +1 -0
@@ -32,6 +32,7 @@ obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
 obj-y += hexdump.o
 obj-$(CONFIG_TEST_HEXDUMP) += test-hexdump.o
 obj-y += kstrtox.o
+obj-y += parse-integer.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
 obj-$(CONFIG_TEST_KASAN) += test_kasan.o
lib/kstrtox.c +4 -23
@@ -20,22 +20,6 @@
 #include <asm/uaccess.h>
 #include "kstrtox.h"
 
-const 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;
-}
-
 /*
  * Convert non-negative integer string representation in explicitly given radix
  * to an integer.
@@ -86,14 +70,11 @@ unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long
 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
 {
 	unsigned long long _res;
-	unsigned int rv;
+	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;
+	rv = parse_integer(s, base, &_res);
+	if (rv < 0)
+		return rv;
 	s += rv;
 	if (*s == '\n')
 		s++;
lib/parse-integer.c new file +180 -0

180 lines not on this page · raw message

#1 lore raw
Quoted 1 line · Alexey Dobriyan
	int parse_integer(const char *s, unsigned int base, T *val);

This is an example how conversion looks like (for mm/ directory):

mm/memcontrol.c +10 -7
@@ -4187,20 +4187,23 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
 	struct fd efile;
 	struct fd cfile;
 	const char *name;
-	char *endp;
 	int ret;
 
 	buf = strstrip(buf);
 
-	efd = simple_strtoul(buf, &endp, 10);
-	if (*endp != ' ')
+	ret = parse_integer(buf, 10, &efd);
+	if (ret < 0)
+		return ret;
+	if (buf[ret] != ' ')
 		return -EINVAL;
-	buf = endp + 1;
+	buf += ret + 1;
 
-	cfd = simple_strtoul(buf, &endp, 10);
-	if ((*endp != ' ') && (*endp != '\0'))
+	ret = parse_integer(buf, 10, &cfd);
+	if (ret < 0)
+		return ret;
+	if (buf[ret] != ' ' && buf[ret] != '\0')
 		return -EINVAL;
-	buf = endp + 1;
+	buf += ret + 1;
 
 	event = kzalloc(sizeof(*event), GFP_KERNEL);
 	if (!event)
mm/page_alloc.c +1 -1
@@ -5977,7 +5977,7 @@ static int __init set_hashdist(char *str)
 {
 	if (!str)
 		return 0;
-	hashdist = simple_strtoul(str, &str, 0);
+	parse_integer(str, 0, &hashdist);
 	return 1;
 }
 __setup("hashdist=", set_hashdist);
mm/shmem.c +8 -6
@@ -2742,6 +2742,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
 	struct mempolicy *mpol = NULL;
 	uid_t uid;
 	gid_t gid;
+	int rv;
 
 	while (options != NULL) {
 		this_char = options;
@@ -2795,14 +2796,15 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
 		} else if (!strcmp(this_char,"mode")) {
 			if (remount)
 				continue;
-			sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
-			if (*rest)
+			rv = parse_integer(value, 8, &sbinfo->mode);
+			if (rv < 0 || value[rv])
 				goto bad_val;
+			sbinfo->mode &= 07777;
 		} else if (!strcmp(this_char,"uid")) {
 			if (remount)
 				continue;
-			uid = simple_strtoul(value, &rest, 0);
-			if (*rest)
+			rv = parse_integer(value, 0, &uid);
+			if (rv < 0 || value[rv])
 				goto bad_val;
 			sbinfo->uid = make_kuid(current_user_ns(), uid);
 			if (!uid_valid(sbinfo->uid))
@@ -2810,8 +2812,8 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
 		} else if (!strcmp(this_char,"gid")) {
 			if (remount)
 				continue;
-			gid = simple_strtoul(value, &rest, 0);
-			if (*rest)
+			rv = parse_integer(value, 0, &gid);
+			if (rv < 0 || value[rv])
 				goto bad_val;
 			sbinfo->gid = make_kgid(current_user_ns(), gid);
 			if (!gid_valid(sbinfo->gid))
maintainer
#2 lore raw
In reply to Alexey Dobriyan
Quoted 7 lines · On Thu, 9 Apr 2015 18:26:14 +0300 Alexey Dobriyan <[email protected]> wrote:

kstrto*() and kstrto*_from_user() family of functions were added help with parsing one integer written as string to proc/sysfs/debugfs files and pass it elsewhere. But they have a limitation: string passed must end with \0 or \n\0. There are enough places where kstrto*() functions can't be used because of this limitation. Trivial example:
parse "%u.%u".

Quoted 7 lines

...

 include/linux/kernel.h |   72 +++++++++++++++++++
 lib/Makefile           |    1 
 lib/kstrtox.c          |   27 +------
 lib/parse-integer.c    |  180 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 257 insertions(+), 23 deletions(-)

That's a lot of code for something which is almost the same as kstrtofoo().

Can we hack up _kstrtoull() to optionally provide the new behaviour? We could use the top bit of `base' to select the behaviour. Something like

lib/kstrtox.c renamed from lib/kstrtox.c~a +11 -7
@@ -87,19 +87,23 @@ static int _kstrtoull(const char *s, uns
 {
 	unsigned long long _res;
 	unsigned int rv;
+	const char *cursor;
+	const unsigned int __base = base & 0x7fffffff;
 
-	s = _parse_integer_fixup_radix(s, &base);
-	rv = _parse_integer(s, base, &_res);
+	cursor = _parse_integer_fixup_radix(s, &__base);
+	rv = _parse_integer(cursor, __base, &_res);
 	if (rv & KSTRTOX_OVERFLOW)
 		return -ERANGE;
 	if (rv == 0)
 		return -EINVAL;
-	s += rv;
-	if (*s == '\n')
-		s++;
-	if (*s)
-		return -EINVAL;
+	cursor += rv;
 	*res = _res;
+	if (base & 0x80000000)
+		return cursor - s;
+	if (*cursor == '\n')
+		cursor++;
+	if (*cursor)
+		return -EINVAL;
 	return 0;
 }
 

then add a bunch of wrappers?

#3 lore raw
Quoted 17 lines · Andrew Morton
Quoted 7 lines · On Thu, 9 Apr 2015 18:26:14 +0300 Alexey Dobriyan <[email protected]> wrote:

kstrto*() and kstrto*_from_user() family of functions were added help with parsing one integer written as string to proc/sysfs/debugfs files and pass it elsewhere. But they have a limitation: string passed must end with \0 or \n\0. There are enough places where kstrto*() functions can't be used because of this limitation. Trivial example:
parse "%u.%u".

Quoted 7 lines

...

 include/linux/kernel.h |   72 +++++++++++++++++++
 lib/Makefile           |    1 
 lib/kstrtox.c          |   27 +------
 lib/parse-integer.c    |  180 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 257 insertions(+), 23 deletions(-)
Quoted 5 lines

That's a lot of code for something which is almost the same as kstrtofoo().

Can we hack up _kstrtoull() to optionally provide the new behaviour? We could use the top bit of `base' to select the behaviour.

Hmm, OK. I did it the opposite way, though. parse_integer() becomes core interface, kstrto*() become wrappers.

Alexey

#4 lore raw

PATCH 1/2 Add parse_integer() (replacement for simple_strto*())

kstrto*() and kstrto*_from_user() family of functions were added help with parsing one integer written as string to proc/sysfs/debugfs files and pass it elsewhere. But they have a limitation: string passed must end with \0 or \n\0. There are enough places where kstrto*() functions can't be used because of this limitation. Trivial example:
parse "%u.%u".

Currently the only way to parse everything is simple_strto*() family of functions. But they are suboptimal:
* they do not detect overflow,
* there are only 2(4) of them -- long and "long long" version. This leads to silent truncation in the most simple case:

	val = strtoul(s, NULL, 0);

* half of the people think that "char **endp" argument is necessary and add unnecessary variable.

OpenBSD people, fed up with how complex correct integer parsing is, added strtonum(3) to fixup for deficiencies of libc-style integer parsing:
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/strtonum.3?query=strtonum&arch=i386

It'd be OK to copy that but it relies on "errno" and fixed strings as error-reporting channel which I think is not OK for kernel. strtonum() also doesn't report number of characted consumed.

What to do?

Enter parse_integer().

	int parse_integer(const char *s, unsigned int base, T *val);

Rationale:

* parse_integer() is exactly 1 (one) interface not 2 or many, one for each type.
* parse_integer() reports -E errors reliably in a canonical kernel way:

	rv = parse_integer(str, 10, &val);
	if (rv < 0)
		return rv;

* parse_integer() writes result only if there were no errors, at least one digit was consumed.
* parse_integer doesn't mix error reporting channel and value channel, it does mix error and number-of-character-consumed channel, though.

* parse_integer() reports number of characters consumed, makes parsing multiple values easy:

	rv = parse_integer(str, 0, &val1);
	if (rv < 0)
		return rv;
	s += rv;
	if (s != '.')
		return -EINVAL;
	rv = parse_integer(str, 0, &val2);
	if (rv < 0)
		return rv;
	if (str[rv] != '\0')
		return -EINVAL;

There are several deficiencies in parse_integer() compared to strto*():
* can't be used in initializers:

	const T x = strtoul();

* can't be used with bitfields,
* can't be used in experessions:

	x = strtol() * 1024;
	x = y = strtol() * 1024;
	x += strtol();

In defense of parse_integer() all I can say, is that using strtol() in expression or initializer promotes no error checking and thus probably should not be encouraged in C, language with no built-in error checking anyway.

The amount of "x = y = strtol()" expressions in kernel is very small. The amount of direct usage in expression is not small, but can be counted as an acceptable loss.

---

 include/linux/kernel.h        |    3 
 include/linux/parse-integer.h |   79 ++++++++++++++++
 lib/Makefile                  |    1 
 lib/kstrtox.c                 |   76 ++++-----------
 lib/kstrtox.h                 |    1 
 lib/parse-integer.c           |  203 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 307 insertions(+), 56 deletions(-)
include/linux/kernel.h +2 -1
@@ -10,6 +10,7 @@
 #include <linux/bitops.h>
 #include <linux/log2.h>
 #include <linux/typecheck.h>
+#include <linux/parse-integer.h>
 #include <linux/printk.h>
 #include <linux/dynamic_debug.h>
 #include <asm/byteorder.h>
@@ -375,7 +376,7 @@ static inline int __must_check kstrtos32_from_user(const char __user *s, size_t
 	return kstrtoint_from_user(s, count, base, res);
 }
 
-/* Obsolete, do not use.  Use kstrto<foo> instead */
+/* Obsolete, do not use. Use parse_integer(), kstrto*() or kstrto*_from_user(). */
 
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
include/linux/parse-integer.h new file +79 -0

79 lines not on this page · raw message

lib/Makefile +1 -0
@@ -32,6 +32,7 @@ obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
 obj-y += hexdump.o
 obj-$(CONFIG_TEST_HEXDUMP) += test-hexdump.o
 obj-y += kstrtox.o
+obj-y += parse-integer.o
 obj-$(CONFIG_TEST_BPF) += test_bpf.o
 obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
 obj-$(CONFIG_TEST_KASAN) += test_kasan.o
lib/kstrtox.c +22 -54

103 lines not on this page · raw message

lib/kstrtox.h +0 -1
@@ -2,7 +2,6 @@
 #define _LIB_KSTRTOX_H
 
 #define KSTRTOX_OVERFLOW	(1U << 31)
-const char *_parse_integer_fixup_radix(const char *s, unsigned int *base);
 unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res);
 
 #endif
lib/parse-integer.c new file +203 -0

203 lines not on this page · raw message

Signature · 1 line
2.0.4
#5 lore raw

PATCH 2/2 parse_integer: rewrite kstrto*()

Rewrite kstrto*() functions through parse_integer().

_kstrtoul() and _kstrtol() are removed because parse_integer() can dispatch based on BITS_PER_LONG saving function call.

Also move function definitions and comment one instance. Remove redundant boilerplate comments from elsewhere.

---

 include/linux/kernel.h        |  124 -----------------------
 include/linux/parse-integer.h |  111 +++++++++++++++++++++
 lib/kstrtox.c                 |  222 ------------------------------------------
 lib/parse-integer.c           |   38 ++++++-
 4 files changed, 145 insertions(+), 350 deletions(-)
include/linux/kernel.h +0 -124
@@ -252,130 +252,6 @@ void do_exit(long error_code)
 void complete_and_exit(struct completion *, long)
 	__noreturn;
 
-/* Internal, do not use. */
-int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res);
-int __must_check _kstrtol(const char *s, unsigned int base, long *res);
-
-int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res);
-int __must_check kstrtoll(const char *s, unsigned int base, long long *res);
-
-/**
- * kstrtoul - convert a string to an unsigned 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.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
-*/
-static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res)
-{
-	/*
-	 * We want to shortcut function call, but
-	 * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0.
-	 */
-	if (sizeof(unsigned long) == sizeof(unsigned long long) &&
-	    __alignof__(unsigned long) == __alignof__(unsigned long long))
-		return kstrtoull(s, base, (unsigned long long *)res);
-	else
-		return _kstrtoul(s, base, res);
-}
-
-/**
- * kstrtol - convert a string to a 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.
- * Used as a replacement for the obsolete simple_strtoull. Return code must
- * be checked.
- */
-static inline int __must_check kstrtol(const char *s, unsigned int base, long *res)
-{
-	/*
-	 * We want to shortcut function call, but
-	 * __builtin_types_compatible_p(long, long long) = 0.
-	 */
-	if (sizeof(long) == sizeof(long long) &&
-	    __alignof__(long) == __alignof__(long long))
-		return kstrtoll(s, base, (long long *)res);
-	else
-		return _kstrtol(s, base, res);
-}
-
-int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res);
-int __must_check kstrtoint(const char *s, unsigned int base, int *res);
-
-static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res)
-{
-	return kstrtoull(s, base, res);
-}
-
-static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res)
-{
-	return kstrtoll(s, base, res);
-}
-
-static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res)
-{
-	return kstrtouint(s, base, res);
-}
-
-static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res)
-{
-	return kstrtoint(s, base, res);
-}
-
-int __must_check kstrtou16(const char *s, unsigned int base, u16 *res);
-int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
-int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
-int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
-
-int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
-int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
-int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res);
-int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res);
-int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res);
-int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res);
-int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res);
-int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
-int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
-int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
-
-static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
-{
-	return kstrtoull_from_user(s, count, base, res);
-}
-
-static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res)
-{
-	return kstrtoll_from_user(s, count, base, res);
-}
-
-static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res)
-{
-	return kstrtouint_from_user(s, count, base, res);
-}
-
-static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res)
-{
-	return kstrtoint_from_user(s, count, base, res);
-}
-
 /* Obsolete, do not use. Use parse_integer(), kstrto*() or kstrto*_from_user(). */
 
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
include/linux/parse-integer.h +111 -0

116 lines not on this page · raw message

lib/kstrtox.c +0 -222

228 lines not on this page · raw message

lib/parse-integer.c +34 -4
@@ -31,7 +31,7 @@ const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
 	return s;
 }
 
-static int __parse_integer(const char *s, unsigned int base, unsigned long long *val)
+static int ___parse_integer(const char *s, unsigned int base, unsigned long long *val)
 {
 	const char *s0 = s, *sd;
 	unsigned long long acc;
@@ -63,6 +63,27 @@ static int __parse_integer(const char *s, unsigned int base, unsigned long long
 	return s - s0;
 }
 
+static int __parse_integer(const char *s, unsigned int base, unsigned long long *val)
+{
+	if (base & PARSE_INTEGER_NEWLINE) {
+		unsigned long long _val;
+		int rv;
+
+		/* Accept "integer\0" or "integer\n\0" */
+		rv = ___parse_integer(s, base & ~PARSE_INTEGER_NEWLINE, &_val);
+		if (rv < 0)
+			return rv;
+		s += rv;
+		if (*s == '\n')
+			s++;
+		if (*s)
+			return -EINVAL;
+		*val = _val;
+		return 0;
+	} else
+		return ___parse_integer(s, base, val);
+}
+
 int _parse_integer_ull(const char *s, unsigned int base, unsigned long long *val)
 {
 	int rv;
@@ -73,7 +94,10 @@ int _parse_integer_ull(const char *s, unsigned int base, unsigned long long *val
 		rv = __parse_integer(s + 1, base, val);
 		if (rv < 0)
 			return rv;
-		return rv + 1;
+		if (base & PARSE_INTEGER_NEWLINE)
+			return 0;
+		else
+			return rv + 1;
 	} else
 		return __parse_integer(s, base, val);
 }
@@ -91,7 +115,10 @@ int _parse_integer_ll(const char *s, unsigned int base, long long *val)
 		if ((long long)-tmp >= 0)
 			return -ERANGE;
 		*val = -tmp;
-		return rv + 1;
+		if (base & PARSE_INTEGER_NEWLINE)
+			return 0;
+		else
+			return rv + 1;
 	} else if (*s == '+') {
 		rv = __parse_integer(s + 1, base, &tmp);
 		if (rv < 0)
@@ -99,7 +126,10 @@ int _parse_integer_ll(const char *s, unsigned int base, long long *val)
 		if ((long long)tmp < 0)
 			return -ERANGE;
 		*val = tmp;
-		return rv + 1;
+		if (base & PARSE_INTEGER_NEWLINE)
+			return 0;
+		else
+			return rv + 1;
 	} else {
 		rv = __parse_integer(s, base, &tmp);
 		if (rv < 0)
Signature · 1 line
2.0.4