xref: /openbmc/linux/lib/parser.c (revision 5b448065)
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);
362