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