XenevaOS
Loading...
Searching...
No Matches
kstrtox.h
Go to the documentation of this file.
1#ifndef __LINUX_KSTRTOX_H__
2#define __LINUX_KSTRTOX_H__
3
4#include <stdbool.h> /* bool, for kstrtobool's out parameter */
5
6/*
7 * DCL <linux/kstrtox.h> -- kstrtou8(), the only string-to-number helper any
8 * ported file has asked for so far.
9 *
10 * The caller is rx_trig_bytes_store at 8250_port.c:3078:
11 *
12 * ret = kstrtou8(buf, 10, &bytes);
13 *
14 * which parses a number a userspace write() put in the sysfs attribute. It
15 * has to be a real parser, not a stub: this is the one place where a value
16 * crosses from userspace into the driver, and a parser that returned a
17 * constant would let a write appear to succeed while programming something
18 * else. The three failure returns matter for the same reason -- the caller
19 * tests `ret` and answers write() with it, so -EINVAL is what turns a bad
20 * write into EIO at the syscall rather than a silent acceptance.
21 *
22 * Deliberately hand-rolled: DCL has no strtol family anywhere in BaseHdr (the
23 * only formatters are _sprintf/_snprintf in <Log/_print.h>), and pulling a
24 * whole formatted-input facility in for one two-digit field would be the
25 * "speculative surface" <linux/cleanup.h> warns about. If a later stage
26 * needs kstrtoint/kstrtoul, they belong here beside it, not in a second header.
27 *
28 * upstream include/linux/kstrtox.h (mainline v7.2), return-value contract
29 * unchanged: 0, -EINVAL for a malformed string, -ERANGE if it does not fit.
30 */
31#include <linux/errno.h> /* -EINVAL, -ERANGE */
32#include <linux/types.h> /* u8 */
33
34static inline int kstrtou8(const char* s, unsigned int base, u8* res)
35{
36 unsigned long v = 0;
37 int any = 0;
38
39 if (!s || !res || (base != 0 && base != 10 && base != 16))
40 return -EINVAL;
41
42 while (*s == ' ' || *s == '\t')
43 s++;
44 if (*s == '-')
45 return -EINVAL; /* unsigned: a sign is a parse error, not a wrap */
46 if ((base == 0 || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
47 base = 16;
48 s += 2;
49 } else if (base == 0) {
50 base = 10;
51 }
52
53 for (;; s++) {
54 unsigned int d;
55
56 if (*s >= '0' && *s <= '9')
57 d = (unsigned int)(*s - '0');
58 else if (base == 16 && *s >= 'a' && *s <= 'f')
59 d = (unsigned int)(*s - 'a') + 10;
60 else if (base == 16 && *s >= 'A' && *s <= 'F')
61 d = (unsigned int)(*s - 'A') + 10;
62 else
63 break;
64
65 if (d >= base)
66 break;
67 v = v * base + d;
68 if (v > 0xFFUL)
69 return -ERANGE;
70 any = 1;
71 }
72
73 /* sysfs buffers arrive newline-terminated; a single trailing \n is part
74 * of the format, anything else after the digits is not. */
75 while (*s == ' ' || *s == '\t')
76 s++;
77 if (*s == '\n')
78 s++;
79 if (*s != '\0' || !any)
80 return -EINVAL;
81
82 *res = (u8)v;
83 return 0;
84}
85
86
87/*
88 * kstrtobool(buf, res) -- parse the text form of a boolean.
89 *
90 * The caller is the `console` sysfs store at serial_core.c:2980, which reads
91 * a line from userspace and turns it into the CON_ENABLED bit. So the token
92 * set is mainline's, and it has to be *exactly* mainline's: userspace writes
93 * "Y", "1", "on" and "N", "0", "off" expecting those spellings to work, and
94 * an answer of -EINVAL for an unrecognised token is what makes a bad write
95 * fail at the syscall rather than silently disable the console.
96 *
97 * A single trailing newline is tolerated (the sysfs buffer carries one);
98 * everything else after the token is an error. Unlike kstrtou8() above,
99 * both branches are short -- no accumulation, no range to check -- so this
100 * stays a two-comparison function rather than sharing its loop.
101 *
102 * upstream include/linux/kstrtox.h (mainline v7.2)
103 */
104static inline int kstrtobool(const char* s, bool* res)
105{
106 const char* p = s;
107 bool v;
108
109 if (!s || !res)
110 return -EINVAL;
111
112 switch (*p)
113 {
114 case 'y': case 'Y': case '1':
115 v = true;
116 p++;
117 break;
118 case 'n': case 'N': case '0':
119 v = false;
120 p++;
121 break;
122 case 'o': case 'O':
123 /* "on" and "off" are the two things 'o' can start, and they mean
124 * opposite things -- so both letters have to be read before the
125 * value is decided, not just the first. The first version of
126 * this function branched on the first letter alone and reported
127 * "off" as true, which is exactly the bug a hand-rolled parser
128 * earns. */
129 p++;
130 if (*p == 'n' || *p == 'N')
131 {
132 v = true;
133 p++;
134 }
135 else if ((*p == 'f' || *p == 'F') &&
136 (p[1] == 'f' || p[1] == 'F'))
137 {
138 v = false;
139 p += 2;
140 }
141 else
142 {
143 return -EINVAL;
144 }
145 break;
146 default:
147 return -EINVAL;
148 }
149
150 /* The sysfs store buffer carries one newline; anything else left over
151 * is a second token the writer did not mean to send ("1 1"), and
152 * accepting it would let a malformed write take effect off the
153 * well-formed prefix alone. */
154 if (*p == '\n')
155 p++;
156 if (*p != '\0')
157 return -EINVAL;
158
159 *res = v;
160 return 0;
161}
162
163
164/*
165 * simple_strtoull() and simple_strtoul() -- and the "simple" in the name is
166 * a warning about the contract, not a comment on the code.
167 *
168 * They differ from kstrtoull()/kstrtoul() in exactly the one way that
169 * matters at their two call sites, and it is why mainline's own doc comment
170 * on these reads "This function has caveats. Please use kstrtoull instead.":
171 * no sign rejection, no end-of-string check, no error return. They consume
172 * digits until one does not fit the radix and hand back whatever accumulated,
173 * leaving *endp at the stopping character. Both callers here pass endp as
174 * NULL, so what they want is the value and nothing else. A kstrtoull() in
175 * their place would reject every one of them:
176 *
177 * serial_core.c:2136 *addr = simple_strtoull(p, NULL, 0);
178 * uart_parse_earlycon(), whose string is an MMIO address followed by
179 * ",options". kstrtoull() demands a NUL immediately after the digits
180 * and would refuse the comma, so no earlycon= would ever parse.
181 * The comment mainline leaves above this line says the same thing in
182 * one line: "Before you replace it with kstrtoull(), think about
183 * options separator (',') it will not tolerate."
184 *
185 * serial_core.c:2164 *baud = simple_strtoul(s, NULL, 10);
186 * uart_parse_options(), whose format is <baud><parity><bits><flow> --
187 * "115200n8r". There is no NUL after the digits by design, so the
188 * strict parser would read nothing at all and every console= would
189 * come up with a baud rate of 0.
190 *
191 * The radix fixup is mainline's _parse_integer_fixup_radix() with the same
192 * answers: base 0 means autodetect, where "0x" followed by a hex digit means
193 * 16, a leading "0" means 8, otherwise 10 -- and the "0x" prefix is skipped
194 * only when base 16 was asked for or arrived at. Two consequences worth
195 * writing down, because they look like bugs and are not: a bare "0" is
196 * parsed as octal, so simple_strtoul("09", 0) stops after the '0' and
197 * returns 0; and with base 0, "0x" *without* a hex digit after it selects
198 * radix 8, which consumes nothing more. That is what a 32-bit kernel does
199 * too, and changing it here would make DCL disagree with the hardware it is
200 * parsing command lines for.
201 *
202 * LLP64 note: simple_strtoul() returns `unsigned long`, four bytes on this
203 * target, so it truncates what simple_strtoull() produced. That is not a
204 * defect this port introduced -- it is mainline's behaviour on every 32-bit
205 * kernel -- and the saturating path below runs first, so an over-long parse
206 * yields 0xFFFFFFFF rather than a value that merely happened to fit in the
207 * low word. The single caller assigns to an int baud rate.
208 *
209 * mainline's _parse_integer_limit() also ORs a KSTRTOX_OVERFLOW bit into
210 * its return, which simple_strntoull() immediately masks back off -- so the
211 * bit is not carried through to these two either, and there is nothing here
212 * to carry it in. Saturation to ULLONG_MAX is the whole overflow answer.
213 *
214 * upstream include/linux/kstrtox.h (the declarations), lib/vsprintf.c:112
215 * (simple_strtoull's wrapper), lib/kstrtox.c
216 * (_parse_integer_fixup_radix, _parse_integer_limit)
217 */
218/*
219 * Kernel ctype, not <ctype.h>. DCL's own <ctype.h> declares isspace() and
220 * friends as exported *functions*; linux/ctype.h spells the same names as
221 * macros over _ctype[]. Whichever lands second turns the other's
222 * declarations into garbage -- a function declaration whose name is already
223 * a macro parses as an expression, which is what produced the cascade of
224 * "expected ')'" at the top of BaseHdr/ctype.h. Mainline keeps these apart
225 * because kernel code never sees the userspace header; here both are on the
226 * include path, so the choice of which one a kernel header asks for has to
227 * be deliberate. It is the kernel one.
228 */
229#include <linux/ctype.h> /* isxdigit, for base-0 autodetection */
230
231static inline unsigned long long simple_strtoull(const char* cp, char** endp,
232 unsigned int base)
233{
234 const char* s = cp;
235 unsigned long long result = 0;
236
237 if (base == 0) {
238 if (s[0] == '0') {
239 if ((s[1] == 'x' || s[1] == 'X') && isxdigit(s[2]))
240 base = 16;
241 else
242 base = 8;
243 } else {
244 base = 10;
245 }
246 }
247 if (base == 16 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
248 s += 2;
249
250 for (;; s++) {
251 unsigned int c = (unsigned char)*s;
252 unsigned int val;
253
254 if ('0' <= c && c <= '9')
255 val = c - '0';
256 else if ('a' <= c && c <= 'f')
257 val = c - 'a' + 10;
258 else if ('A' <= c && c <= 'F')
259 val = c - 'A' + 10;
260 else
261 break;
262
263 if (val >= base)
264 break;
265
266 /*
267 * mainline guards the multiply with `res & (~0ull << 60)`:
268 * below 2^60, times a base of at most 16, cannot reach 2^64,
269 * so the fast path needs no test at all. Above it, saturate
270 * the way _parse_integer_limit() does. Note the two-part
271 * condition -- the second multiply is only evaluated once the
272 * first has proved it safe.
273 */
274 if (result & (~0ULL << 60)) {
275 if (result > ~0ULL / base ||
276 result * base > ~0ULL - val)
277 result = ~0ULL;
278 else
279 result = result * base + val;
280 } else {
281 result = result * base + val;
282 }
283 }
284
285 if (endp)
286 *endp = (char*)s;
287
288 return result;
289}
290
291static inline unsigned long simple_strtoul(const char* cp, char** endp,
292 unsigned int base)
293{
294 return (unsigned long)simple_strtoull(cp, endp, base);
295}
296
297/*
298 * simple_strtol() -- the signed form, mainline's three-line wrapper
299 * (lib/vsprintf.c):
300 *
301 * if (*cp == '-')
302 * return -simple_strtoul(cp + 1, endp, base);
303 * return simple_strtoul(cp, endp, base);
304 *
305 * drm_modes.c is the whole consumer set, all five calls inside the
306 * command-line parser: :1947 and :1966 read a bpp and a refresh rate,
307 * :2038/:2047 a resolution, :2105 a bare integer option. The sign branch is
308 * the only thing this adds, and it is the point: handed "-32" directly,
309 * simple_strtoul() stops at the '-' and returns 0 with endp on the sign, so
310 * a command line asking for a negative value would parse as zero. Zero is a
311 * value the mode validator later rejects or silently treats as "unset",
312 * which is a wrong answer rather than the parse error the writer deserved --
313 * whereas with the branch the caller receives -32 and can reject it itself.
314 *
315 * '+' is not consumed, and that is mainline's behaviour rather than an
316 * omission: no caller distinguishes a leading plus, and simple_strtoul()
317 * would stop on it identically to any other non-digit. The negation wraps
318 * through unsigned long like mainline's does, so -2147483648 comes out as
319 * LONG_MIN rather than saturating.
320 */
321static inline long simple_strtol(const char* cp, char** endp,
322 unsigned int base)
323{
324 if (*cp == '-')
325 return -simple_strtoul(cp + 1, endp, base);
326 return simple_strtoul(cp, endp, base);
327}
328#endif /* __LINUX_KSTRTOX_H__ */
#define EINVAL
Definition acclib.h:198
#define isxdigit(c)
Definition acclib.h:178
#define ERANGE
Definition acclib.h:200
struct i915_user_extension base
Definition i915_drm.h:0
#define d
Definition libunicode.c:1833
uint8_t u8
Definition kernel.h:14
#define ULL(x)
Definition const.h:79