Add parse_integer() (replacement for simple_strto*())
Subsystems (5)
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 longstatic 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
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))
Andrew Morton
maintainerQuoted 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?
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
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_treturn 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
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 longreturn 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