• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   */
match_one(char * s,const char * p,substring_t args[])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   */
match_token(char * s,const match_table_t table,substring_t args[])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   */
match_number(substring_t * s,int * result,int base)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   */
match_u64int(substring_t * s,u64 * result,int base)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   */
match_int(substring_t * s,int * result)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_u64: - scan a decimal representation of a u64 from
193   *                  a substring_t
194   * @s: substring_t to be scanned
195   * @result: resulting unsigned long long on success
196   *
197   * Description: Attempts to parse the &substring_t @s as a long decimal
198   * integer. On success, sets @result to the integer represented by the
199   * string and returns 0.
200   * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
201   */
match_u64(substring_t * s,u64 * result)202  int match_u64(substring_t *s, u64 *result)
203  {
204  	return match_u64int(s, result, 0);
205  }
206  EXPORT_SYMBOL(match_u64);
207  
208  /**
209   * match_octal: - scan an octal representation of an integer from a substring_t
210   * @s: substring_t to be scanned
211   * @result: resulting integer on success
212   *
213   * Description: Attempts to parse the &substring_t @s as an octal integer. On
214   * success, sets @result to the integer represented by the string and returns
215   * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
216   */
match_octal(substring_t * s,int * result)217  int match_octal(substring_t *s, int *result)
218  {
219  	return match_number(s, result, 8);
220  }
221  EXPORT_SYMBOL(match_octal);
222  
223  /**
224   * match_hex: - scan a hex representation of an integer from a substring_t
225   * @s: substring_t to be scanned
226   * @result: resulting integer on success
227   *
228   * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
229   * On success, sets @result to the integer represented by the string and
230   * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
231   */
match_hex(substring_t * s,int * result)232  int match_hex(substring_t *s, int *result)
233  {
234  	return match_number(s, result, 16);
235  }
236  EXPORT_SYMBOL(match_hex);
237  
238  /**
239   * match_wildcard: - parse if a string matches given wildcard pattern
240   * @pattern: wildcard pattern
241   * @str: the string to be parsed
242   *
243   * Description: Parse the string @str to check if matches wildcard
244   * pattern @pattern. The pattern may contain two type wildcardes:
245   *   '*' - matches zero or more characters
246   *   '?' - matches one character
247   * If it's matched, return true, else return false.
248   */
match_wildcard(const char * pattern,const char * str)249  bool match_wildcard(const char *pattern, const char *str)
250  {
251  	const char *s = str;
252  	const char *p = pattern;
253  	bool star = false;
254  
255  	while (*s) {
256  		switch (*p) {
257  		case '?':
258  			s++;
259  			p++;
260  			break;
261  		case '*':
262  			star = true;
263  			str = s;
264  			if (!*++p)
265  				return true;
266  			pattern = p;
267  			break;
268  		default:
269  			if (*s == *p) {
270  				s++;
271  				p++;
272  			} else {
273  				if (!star)
274  					return false;
275  				str++;
276  				s = str;
277  				p = pattern;
278  			}
279  			break;
280  		}
281  	}
282  
283  	if (*p == '*')
284  		++p;
285  	return !*p;
286  }
287  EXPORT_SYMBOL(match_wildcard);
288  
289  /**
290   * match_strlcpy: - Copy the characters from a substring_t to a sized buffer
291   * @dest: where to copy to
292   * @src: &substring_t to copy
293   * @size: size of destination buffer
294   *
295   * Description: Copy the characters in &substring_t @src to the
296   * c-style string @dest.  Copy no more than @size - 1 characters, plus
297   * the terminating NUL.  Return length of @src.
298   */
match_strlcpy(char * dest,const substring_t * src,size_t size)299  size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
300  {
301  	size_t ret = src->to - src->from;
302  
303  	if (size) {
304  		size_t len = ret >= size ? size - 1 : ret;
305  		memcpy(dest, src->from, len);
306  		dest[len] = '\0';
307  	}
308  	return ret;
309  }
310  EXPORT_SYMBOL(match_strlcpy);
311  
312  /**
313   * match_strdup: - allocate a new string with the contents of a substring_t
314   * @s: &substring_t to copy
315   *
316   * Description: Allocates and returns a string filled with the contents of
317   * the &substring_t @s. The caller is responsible for freeing the returned
318   * string with kfree().
319   */
match_strdup(const substring_t * s)320  char *match_strdup(const substring_t *s)
321  {
322  	return kmemdup_nul(s->from, s->to - s->from, GFP_KERNEL);
323  }
324  EXPORT_SYMBOL(match_strdup);
325