1 /* 2 * Convert integer string representation to an integer. 3 * If an integer doesn't fit into specified type, -E is returned. 4 * 5 * Integer starts with optional sign. 6 * kstrtou*() functions do not accept sign "-". 7 * 8 * Radix 0 means autodetection: leading "0x" implies radix 16, 9 * leading "0" implies radix 8, otherwise radix is 10. 10 * Autodetection hints work after optional sign, but not before. 11 * 12 * If -E is returned, result is not touched. 13 */ 14 #include <linux/ctype.h> 15 #include <linux/errno.h> 16 #include <linux/kernel.h> 17 #include <linux/math64.h> 18 #include <linux/module.h> 19 #include <linux/types.h> 20 #include <asm/uaccess.h> 21 22 static inline char _tolower(const char c) 23 { 24 return c | 0x20; 25 } 26 27 static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) 28 { 29 unsigned long long acc; 30 int ok; 31 32 if (base == 0) { 33 if (s[0] == '0') { 34 if (_tolower(s[1]) == 'x' && isxdigit(s[2])) 35 base = 16; 36 else 37 base = 8; 38 } else 39 base = 10; 40 } 41 if (base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') 42 s += 2; 43 44 acc = 0; 45 ok = 0; 46 while (*s) { 47 unsigned int val; 48 49 if ('0' <= *s && *s <= '9') 50 val = *s - '0'; 51 else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f') 52 val = _tolower(*s) - 'a' + 10; 53 else if (*s == '\n' && *(s + 1) == '\0') 54 break; 55 else 56 return -EINVAL; 57 58 if (val >= base) 59 return -EINVAL; 60 if (acc > div_u64(ULLONG_MAX - val, base)) 61 return -ERANGE; 62 acc = acc * base + val; 63 ok = 1; 64 65 s++; 66 } 67 if (!ok) 68 return -EINVAL; 69 *res = acc; 70 return 0; 71 } 72 73 int kstrtoull(const char *s, unsigned int base, unsigned long long *res) 74 { 75 if (s[0] == '+') 76 s++; 77 return _kstrtoull(s, base, res); 78 } 79 EXPORT_SYMBOL(kstrtoull); 80 81 int kstrtoll(const char *s, unsigned int base, long long *res) 82 { 83 unsigned long long tmp; 84 int rv; 85 86 if (s[0] == '-') { 87 rv = _kstrtoull(s + 1, base, &tmp); 88 if (rv < 0) 89 return rv; 90 if ((long long)(-tmp) >= 0) 91 return -ERANGE; 92 *res = -tmp; 93 } else { 94 rv = kstrtoull(s, base, &tmp); 95 if (rv < 0) 96 return rv; 97 if ((long long)tmp < 0) 98 return -ERANGE; 99 *res = tmp; 100 } 101 return 0; 102 } 103 EXPORT_SYMBOL(kstrtoll); 104 105 /* Internal, do not use. */ 106 int _kstrtoul(const char *s, unsigned int base, unsigned long *res) 107 { 108 unsigned long long tmp; 109 int rv; 110 111 rv = kstrtoull(s, base, &tmp); 112 if (rv < 0) 113 return rv; 114 if (tmp != (unsigned long long)(unsigned long)tmp) 115 return -ERANGE; 116 *res = tmp; 117 return 0; 118 } 119 EXPORT_SYMBOL(_kstrtoul); 120 121 /* Internal, do not use. */ 122 int _kstrtol(const char *s, unsigned int base, long *res) 123 { 124 long long tmp; 125 int rv; 126 127 rv = kstrtoll(s, base, &tmp); 128 if (rv < 0) 129 return rv; 130 if (tmp != (long long)(long)tmp) 131 return -ERANGE; 132 *res = tmp; 133 return 0; 134 } 135 EXPORT_SYMBOL(_kstrtol); 136 137 int kstrtouint(const char *s, unsigned int base, unsigned int *res) 138 { 139 unsigned long long tmp; 140 int rv; 141 142 rv = kstrtoull(s, base, &tmp); 143 if (rv < 0) 144 return rv; 145 if (tmp != (unsigned long long)(unsigned int)tmp) 146 return -ERANGE; 147 *res = tmp; 148 return 0; 149 } 150 EXPORT_SYMBOL(kstrtouint); 151 152 int kstrtoint(const char *s, unsigned int base, int *res) 153 { 154 long long tmp; 155 int rv; 156 157 rv = kstrtoll(s, base, &tmp); 158 if (rv < 0) 159 return rv; 160 if (tmp != (long long)(int)tmp) 161 return -ERANGE; 162 *res = tmp; 163 return 0; 164 } 165 EXPORT_SYMBOL(kstrtoint); 166 167 int kstrtou16(const char *s, unsigned int base, u16 *res) 168 { 169 unsigned long long tmp; 170 int rv; 171 172 rv = kstrtoull(s, base, &tmp); 173 if (rv < 0) 174 return rv; 175 if (tmp != (unsigned long long)(u16)tmp) 176 return -ERANGE; 177 *res = tmp; 178 return 0; 179 } 180 EXPORT_SYMBOL(kstrtou16); 181 182 int kstrtos16(const char *s, unsigned int base, s16 *res) 183 { 184 long long tmp; 185 int rv; 186 187 rv = kstrtoll(s, base, &tmp); 188 if (rv < 0) 189 return rv; 190 if (tmp != (long long)(s16)tmp) 191 return -ERANGE; 192 *res = tmp; 193 return 0; 194 } 195 EXPORT_SYMBOL(kstrtos16); 196 197 int kstrtou8(const char *s, unsigned int base, u8 *res) 198 { 199 unsigned long long tmp; 200 int rv; 201 202 rv = kstrtoull(s, base, &tmp); 203 if (rv < 0) 204 return rv; 205 if (tmp != (unsigned long long)(u8)tmp) 206 return -ERANGE; 207 *res = tmp; 208 return 0; 209 } 210 EXPORT_SYMBOL(kstrtou8); 211 212 int kstrtos8(const char *s, unsigned int base, s8 *res) 213 { 214 long long tmp; 215 int rv; 216 217 rv = kstrtoll(s, base, &tmp); 218 if (rv < 0) 219 return rv; 220 if (tmp != (long long)(s8)tmp) 221 return -ERANGE; 222 *res = tmp; 223 return 0; 224 } 225 EXPORT_SYMBOL(kstrtos8); 226 227 #define kstrto_from_user(f, g, type) \ 228 int f(const char __user *s, size_t count, unsigned int base, type *res) \ 229 { \ 230 /* sign, base 2 representation, newline, terminator */ \ 231 char buf[1 + sizeof(type) * 8 + 1 + 1]; \ 232 \ 233 count = min(count, sizeof(buf) - 1); \ 234 if (copy_from_user(buf, s, count)) \ 235 return -EFAULT; \ 236 buf[count] = '\0'; \ 237 return g(buf, base, res); \ 238 } \ 239 EXPORT_SYMBOL(f) 240 241 kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long); 242 kstrto_from_user(kstrtoll_from_user, kstrtoll, long long); 243 kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long); 244 kstrto_from_user(kstrtol_from_user, kstrtol, long); 245 kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int); 246 kstrto_from_user(kstrtoint_from_user, kstrtoint, int); 247 kstrto_from_user(kstrtou16_from_user, kstrtou16, u16); 248 kstrto_from_user(kstrtos16_from_user, kstrtos16, s16); 249 kstrto_from_user(kstrtou8_from_user, kstrtou8, u8); 250 kstrto_from_user(kstrtos8_from_user, kstrtos8, s8); 251