diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2011-05-25 02:13:31 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 17:39:52 +0200 |
commit | c196e32a111b0ee356d67acceb938ae0b5e63ef0 (patch) | |
tree | 8759b68d81eb693e391dee8f85a8d418ea5656a6 /lib | |
parent | lru_cache: use correct type in sizeof for allocation (diff) | |
download | linux-c196e32a111b0ee356d67acceb938ae0b5e63ef0.tar.xz linux-c196e32a111b0ee356d67acceb938ae0b5e63ef0.zip |
lib: add kstrto*_from_user()
There is quite a lot of code which does copy_from_user() + strict_strto*()
or simple_strto*() combo in slightly different ways.
Before doing conversions all over tree, let's get final API correct.
Enter kstrtoull_from_user() and friends.
Typical code which uses them looks very simple:
TYPE val;
int rv;
rv = kstrtoTYPE_from_user(buf, count, 0, &val);
if (rv < 0)
return rv;
[use val]
return count;
There is a tiny semantic difference from the plain kstrto*() API -- the
latter allows any amount of leading zeroes, while the former copies data
into buffer on stack and thus allows leading zeroes as long as it fits
into buffer.
This shouldn't be a problem for typical usecase "echo 42 > /proc/x".
The point is to make reading one integer from userspace _very_ simple and
very bug free.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/kstrtox.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/lib/kstrtox.c b/lib/kstrtox.c index a235f3cc471c..2dbae88090ac 100644 --- a/lib/kstrtox.c +++ b/lib/kstrtox.c @@ -17,6 +17,7 @@ #include <linux/math64.h> #include <linux/module.h> #include <linux/types.h> +#include <asm/uaccess.h> static inline char _tolower(const char c) { @@ -222,3 +223,28 @@ int kstrtos8(const char *s, unsigned int base, s8 *res) return 0; } EXPORT_SYMBOL(kstrtos8); + +#define kstrto_from_user(f, g, type) \ +int f(const char __user *s, size_t count, unsigned int base, type *res) \ +{ \ + /* sign, base 2 representation, newline, terminator */ \ + char buf[1 + sizeof(type) * 8 + 1 + 1]; \ + \ + count = min(count, sizeof(buf) - 1); \ + if (copy_from_user(buf, s, count)) \ + return -EFAULT; \ + buf[count] = '\0'; \ + return g(buf, base, res); \ +} \ +EXPORT_SYMBOL(f) + +kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long); +kstrto_from_user(kstrtoll_from_user, kstrtoll, long long); +kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long); +kstrto_from_user(kstrtol_from_user, kstrtol, long); +kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int); +kstrto_from_user(kstrtoint_from_user, kstrtoint, int); +kstrto_from_user(kstrtou16_from_user, kstrtou16, u16); +kstrto_from_user(kstrtos16_from_user, kstrtos16, s16); +kstrto_from_user(kstrtou8_from_user, kstrtou8, u8); +kstrto_from_user(kstrtos8_from_user, kstrtos8, s8); |