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