Merge branch 'akpm' (patches from Andrew)
[platform/kernel/linux-rpi.git] / lib / parser.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * lib/parser.c - simple parser for mount, etc. options.
4  */
5
6 #include <linux/ctype.h>
7 #include <linux/types.h>
8 #include <linux/export.h>
9 #include <linux/parser.h>
10 #include <linux/slab.h>
11 #include <linux/string.h>
12
13 /**
14  * match_one - Determines if a string matches a simple pattern
15  * @s: the string to examine for presence of the pattern
16  * @p: the string containing the pattern
17  * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
18  * locations.
19  *
20  * Description: Determines if the pattern @p is present in string @s. Can only
21  * match extremely simple token=arg style patterns. If the pattern is found,
22  * the location(s) of the arguments will be returned in the @args array.
23  */
24 static int match_one(char *s, const char *p, substring_t args[])
25 {
26         char *meta;
27         int argc = 0;
28
29         if (!p)
30                 return 1;
31
32         while(1) {
33                 int len = -1;
34                 meta = strchr(p, '%');
35                 if (!meta)
36                         return strcmp(p, s) == 0;
37
38                 if (strncmp(p, s, meta-p))
39                         return 0;
40
41                 s += meta - p;
42                 p = meta + 1;
43
44                 if (isdigit(*p))
45                         len = simple_strtoul(p, (char **) &p, 10);
46                 else if (*p == '%') {
47                         if (*s++ != '%')
48                                 return 0;
49                         p++;
50                         continue;
51                 }
52
53                 if (argc >= MAX_OPT_ARGS)
54                         return 0;
55
56                 args[argc].from = s;
57                 switch (*p++) {
58                 case 's': {
59                         size_t str_len = strlen(s);
60
61                         if (str_len == 0)
62                                 return 0;
63                         if (len == -1 || len > str_len)
64                                 len = str_len;
65                         args[argc].to = s + len;
66                         break;
67                 }
68                 case 'd':
69                         simple_strtol(s, &args[argc].to, 0);
70                         goto num;
71                 case 'u':
72                         simple_strtoul(s, &args[argc].to, 0);
73                         goto num;
74                 case 'o':
75                         simple_strtoul(s, &args[argc].to, 8);
76                         goto num;
77                 case 'x':
78                         simple_strtoul(s, &args[argc].to, 16);
79                 num:
80                         if (args[argc].to == args[argc].from)
81                                 return 0;
82                         break;
83                 default:
84                         return 0;
85                 }
86                 s = args[argc].to;
87                 argc++;
88         }
89 }
90
91 /**
92  * match_token - Find a token (and optional args) in a string
93  * @s: the string to examine for token/argument pairs
94  * @table: match_table_t describing the set of allowed option tokens and the
95  * arguments that may be associated with them. Must be terminated with a
96  * &struct match_token whose pattern is set to the NULL pointer.
97  * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
98  * locations.
99  *
100  * Description: Detects which if any of a set of token strings has been passed
101  * to it. Tokens can include up to %MAX_OPT_ARGS instances of basic c-style
102  * format identifiers which will be taken into account when matching the
103  * tokens, and whose locations will be returned in the @args array.
104  */
105 int match_token(char *s, const match_table_t table, substring_t args[])
106 {
107         const struct match_token *p;
108
109         for (p = table; !match_one(s, p->pattern, args) ; p++)
110                 ;
111
112         return p->token;
113 }
114 EXPORT_SYMBOL(match_token);
115
116 /**
117  * match_number - scan a number in the given base from a substring_t
118  * @s: substring to be scanned
119  * @result: resulting integer on success
120  * @base: base to use when converting string
121  *
122  * Description: Given a &substring_t and a base, attempts to parse the substring
123  * as a number in that base.
124  *
125  * Return: On success, sets @result to the integer represented by the
126  * string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
127  */
128 static int match_number(substring_t *s, int *result, int base)
129 {
130         char *endp;
131         char *buf;
132         int ret;
133         long val;
134
135         buf = match_strdup(s);
136         if (!buf)
137                 return -ENOMEM;
138
139         ret = 0;
140         val = simple_strtol(buf, &endp, base);
141         if (endp == buf)
142                 ret = -EINVAL;
143         else if (val < (long)INT_MIN || val > (long)INT_MAX)
144                 ret = -ERANGE;
145         else
146                 *result = (int) val;
147         kfree(buf);
148         return ret;
149 }
150
151 /**
152  * match_u64int - scan a number in the given base from a substring_t
153  * @s: substring to be scanned
154  * @result: resulting u64 on success
155  * @base: base to use when converting string
156  *
157  * Description: Given a &substring_t and a base, attempts to parse the substring
158  * as a number in that base.
159  *
160  * Return: On success, sets @result to the integer represented by the
161  * string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
162  */
163 static int match_u64int(substring_t *s, u64 *result, int base)
164 {
165         char *buf;
166         int ret;
167         u64 val;
168
169         buf = match_strdup(s);
170         if (!buf)
171                 return -ENOMEM;
172
173         ret = kstrtoull(buf, base, &val);
174         if (!ret)
175                 *result = val;
176         kfree(buf);
177         return ret;
178 }
179
180 /**
181  * match_int - scan a decimal representation of an integer from a substring_t
182  * @s: substring_t to be scanned
183  * @result: resulting integer on success
184  *
185  * Description: Attempts to parse the &substring_t @s as a decimal integer.
186  *
187  * Return: On success, sets @result to the integer represented by the string
188  * and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
189  */
190 int match_int(substring_t *s, int *result)
191 {
192         return match_number(s, result, 0);
193 }
194 EXPORT_SYMBOL(match_int);
195
196 /**
197  * match_uint - scan a decimal representation of an integer from a substring_t
198  * @s: substring_t to be scanned
199  * @result: resulting integer on success
200  *
201  * Description: Attempts to parse the &substring_t @s as a decimal integer.
202  *
203  * Return: On success, sets @result to the integer represented by the string
204  * and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
205  */
206 int match_uint(substring_t *s, unsigned int *result)
207 {
208         int err = -ENOMEM;
209         char *buf = match_strdup(s);
210
211         if (buf) {
212                 err = kstrtouint(buf, 10, result);
213                 kfree(buf);
214         }
215         return err;
216 }
217 EXPORT_SYMBOL(match_uint);
218
219 /**
220  * match_u64 - scan a decimal representation of a u64 from
221  *                  a substring_t
222  * @s: substring_t to be scanned
223  * @result: resulting unsigned long long on success
224  *
225  * Description: Attempts to parse the &substring_t @s as a long decimal
226  * integer.
227  *
228  * Return: On success, sets @result to the integer represented by the string
229  * and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
230  */
231 int match_u64(substring_t *s, u64 *result)
232 {
233         return match_u64int(s, result, 0);
234 }
235 EXPORT_SYMBOL(match_u64);
236
237 /**
238  * match_octal - scan an octal representation of an integer from a substring_t
239  * @s: substring_t to be scanned
240  * @result: resulting integer on success
241  *
242  * Description: Attempts to parse the &substring_t @s as an octal integer.
243  *
244  * Return: On success, sets @result to the integer represented by the string
245  * and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
246  */
247 int match_octal(substring_t *s, int *result)
248 {
249         return match_number(s, result, 8);
250 }
251 EXPORT_SYMBOL(match_octal);
252
253 /**
254  * match_hex - scan a hex representation of an integer from a substring_t
255  * @s: substring_t to be scanned
256  * @result: resulting integer on success
257  *
258  * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
259  *
260  * Return: On success, sets @result to the integer represented by the string
261  * and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
262  */
263 int match_hex(substring_t *s, int *result)
264 {
265         return match_number(s, result, 16);
266 }
267 EXPORT_SYMBOL(match_hex);
268
269 /**
270  * match_wildcard - parse if a string matches given wildcard pattern
271  * @pattern: wildcard pattern
272  * @str: the string to be parsed
273  *
274  * Description: Parse the string @str to check if matches wildcard
275  * pattern @pattern. The pattern may contain two types of wildcards:
276  *   '*' - matches zero or more characters
277  *   '?' - matches one character
278  *
279  * Return: If the @str matches the @pattern, return true, else return false.
280  */
281 bool match_wildcard(const char *pattern, const char *str)
282 {
283         const char *s = str;
284         const char *p = pattern;
285         bool star = false;
286
287         while (*s) {
288                 switch (*p) {
289                 case '?':
290                         s++;
291                         p++;
292                         break;
293                 case '*':
294                         star = true;
295                         str = s;
296                         if (!*++p)
297                                 return true;
298                         pattern = p;
299                         break;
300                 default:
301                         if (*s == *p) {
302                                 s++;
303                                 p++;
304                         } else {
305                                 if (!star)
306                                         return false;
307                                 str++;
308                                 s = str;
309                                 p = pattern;
310                         }
311                         break;
312                 }
313         }
314
315         if (*p == '*')
316                 ++p;
317         return !*p;
318 }
319 EXPORT_SYMBOL(match_wildcard);
320
321 /**
322  * match_strlcpy - Copy the characters from a substring_t to a sized buffer
323  * @dest: where to copy to
324  * @src: &substring_t to copy
325  * @size: size of destination buffer
326  *
327  * Description: Copy the characters in &substring_t @src to the
328  * c-style string @dest.  Copy no more than @size - 1 characters, plus
329  * the terminating NUL.
330  *
331  * Return: length of @src.
332  */
333 size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
334 {
335         size_t ret = src->to - src->from;
336
337         if (size) {
338                 size_t len = ret >= size ? size - 1 : ret;
339                 memcpy(dest, src->from, len);
340                 dest[len] = '\0';
341         }
342         return ret;
343 }
344 EXPORT_SYMBOL(match_strlcpy);
345
346 /**
347  * match_strdup - allocate a new string with the contents of a substring_t
348  * @s: &substring_t to copy
349  *
350  * Description: Allocates and returns a string filled with the contents of
351  * the &substring_t @s. The caller is responsible for freeing the returned
352  * string with kfree().
353  *
354  * Return: the address of the newly allocated NUL-terminated string or
355  * %NULL on error.
356  */
357 char *match_strdup(const substring_t *s)
358 {
359         return kmemdup_nul(s->from, s->to - s->from, GFP_KERNEL);
360 }
361 EXPORT_SYMBOL(match_strdup);