xref: /linux/lib/parser.c (revision 163b099146b85d1b05bd2eaa045acbeee25c29e4)
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. On success, sets @result to the integer represented
124   * by the string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
125   */
126  static int match_number(substring_t *s, int *result, int base)
127  {
128  	char *endp;
129  	char *buf;
130  	int ret;
131  	long val;
132  
133  	buf = match_strdup(s);
134  	if (!buf)
135  		return -ENOMEM;
136  
137  	ret = 0;
138  	val = simple_strtol(buf, &endp, base);
139  	if (endp == buf)
140  		ret = -EINVAL;
141  	else if (val < (long)INT_MIN || val > (long)INT_MAX)
142  		ret = -ERANGE;
143  	else
144  		*result = (int) val;
145  	kfree(buf);
146  	return ret;
147  }
148  
149  /**
150   * match_u64int - scan a number in the given base from a substring_t
151   * @s: substring to be scanned
152   * @result: resulting u64 on success
153   * @base: base to use when converting string
154   *
155   * Description: Given a &substring_t and a base, attempts to parse the substring
156   * as a number in that base. On success, sets @result to the integer represented
157   * by the string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
158   */
159  static int match_u64int(substring_t *s, u64 *result, int base)
160  {
161  	char *buf;
162  	int ret;
163  	u64 val;
164  
165  	buf = match_strdup(s);
166  	if (!buf)
167  		return -ENOMEM;
168  
169  	ret = kstrtoull(buf, base, &val);
170  	if (!ret)
171  		*result = val;
172  	kfree(buf);
173  	return ret;
174  }
175  
176  /**
177   * match_int - scan a decimal representation of an integer from a substring_t
178   * @s: substring_t to be scanned
179   * @result: resulting integer on success
180   *
181   * Description: Attempts to parse the &substring_t @s as a decimal integer. On
182   * success, sets @result to the integer represented by the string and returns 0.
183   * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
184   */
185  int match_int(substring_t *s, int *result)
186  {
187  	return match_number(s, result, 0);
188  }
189  EXPORT_SYMBOL(match_int);
190  
191  /*
192   * match_uint - scan a decimal representation of an integer from a substring_t
193   * @s: substring_t to be scanned
194   * @result: resulting integer on success
195   *
196   * Description: Attempts to parse the &substring_t @s as a decimal integer. On
197   * success, sets @result to the integer represented by the string and returns 0.
198   * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
199   */
200  int match_uint(substring_t *s, unsigned int *result)
201  {
202  	int err = -ENOMEM;
203  	char *buf = match_strdup(s);
204  
205  	if (buf) {
206  		err = kstrtouint(buf, 10, result);
207  		kfree(buf);
208  	}
209  	return err;
210  }
211  EXPORT_SYMBOL(match_uint);
212  
213  /**
214   * match_u64 - scan a decimal representation of a u64 from
215   *                  a substring_t
216   * @s: substring_t to be scanned
217   * @result: resulting unsigned long long on success
218   *
219   * Description: Attempts to parse the &substring_t @s as a long decimal
220   * integer. On success, sets @result to the integer represented by the
221   * string and returns 0.
222   * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
223   */
224  int match_u64(substring_t *s, u64 *result)
225  {
226  	return match_u64int(s, result, 0);
227  }
228  EXPORT_SYMBOL(match_u64);
229  
230  /**
231   * match_octal - scan an octal representation of an integer from a substring_t
232   * @s: substring_t to be scanned
233   * @result: resulting integer on success
234   *
235   * Description: Attempts to parse the &substring_t @s as an octal integer. On
236   * success, sets @result to the integer represented by the string and returns
237   * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
238   */
239  int match_octal(substring_t *s, int *result)
240  {
241  	return match_number(s, result, 8);
242  }
243  EXPORT_SYMBOL(match_octal);
244  
245  /**
246   * match_hex - scan a hex representation of an integer from a substring_t
247   * @s: substring_t to be scanned
248   * @result: resulting integer on success
249   *
250   * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
251   * On success, sets @result to the integer represented by the string and
252   * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
253   */
254  int match_hex(substring_t *s, int *result)
255  {
256  	return match_number(s, result, 16);
257  }
258  EXPORT_SYMBOL(match_hex);
259  
260  /**
261   * match_wildcard - parse if a string matches given wildcard pattern
262   * @pattern: wildcard pattern
263   * @str: the string to be parsed
264   *
265   * Description: Parse the string @str to check if matches wildcard
266   * pattern @pattern. The pattern may contain two type wildcardes:
267   *   '*' - matches zero or more characters
268   *   '?' - matches one character
269   * If it's matched, return true, else return false.
270   */
271  bool match_wildcard(const char *pattern, const char *str)
272  {
273  	const char *s = str;
274  	const char *p = pattern;
275  	bool star = false;
276  
277  	while (*s) {
278  		switch (*p) {
279  		case '?':
280  			s++;
281  			p++;
282  			break;
283  		case '*':
284  			star = true;
285  			str = s;
286  			if (!*++p)
287  				return true;
288  			pattern = p;
289  			break;
290  		default:
291  			if (*s == *p) {
292  				s++;
293  				p++;
294  			} else {
295  				if (!star)
296  					return false;
297  				str++;
298  				s = str;
299  				p = pattern;
300  			}
301  			break;
302  		}
303  	}
304  
305  	if (*p == '*')
306  		++p;
307  	return !*p;
308  }
309  EXPORT_SYMBOL(match_wildcard);
310  
311  /**
312   * match_strlcpy - Copy the characters from a substring_t to a sized buffer
313   * @dest: where to copy to
314   * @src: &substring_t to copy
315   * @size: size of destination buffer
316   *
317   * Description: Copy the characters in &substring_t @src to the
318   * c-style string @dest.  Copy no more than @size - 1 characters, plus
319   * the terminating NUL.  Return length of @src.
320   */
321  size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
322  {
323  	size_t ret = src->to - src->from;
324  
325  	if (size) {
326  		size_t len = ret >= size ? size - 1 : ret;
327  		memcpy(dest, src->from, len);
328  		dest[len] = '\0';
329  	}
330  	return ret;
331  }
332  EXPORT_SYMBOL(match_strlcpy);
333  
334  /**
335   * match_strdup - allocate a new string with the contents of a substring_t
336   * @s: &substring_t to copy
337   *
338   * Description: Allocates and returns a string filled with the contents of
339   * the &substring_t @s. The caller is responsible for freeing the returned
340   * string with kfree().
341   */
342  char *match_strdup(const substring_t *s)
343  {
344  	return kmemdup_nul(s->from, s->to - s->from, GFP_KERNEL);
345  }
346  EXPORT_SYMBOL(match_strdup);
347