162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * lib/parser.c - simple parser for mount, etc. options.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/ctype.h>
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <linux/export.h>
962306a36Sopenharmony_ci#include <linux/kstrtox.h>
1062306a36Sopenharmony_ci#include <linux/parser.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * max size needed by different bases to express U64
1662306a36Sopenharmony_ci * HEX: "0xFFFFFFFFFFFFFFFF" --> 18
1762306a36Sopenharmony_ci * DEC: "18446744073709551615" --> 20
1862306a36Sopenharmony_ci * OCT: "01777777777777777777777" --> 23
1962306a36Sopenharmony_ci * pick the max one to define NUMBER_BUF_LEN
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci#define NUMBER_BUF_LEN 24
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/**
2462306a36Sopenharmony_ci * match_one - Determines if a string matches a simple pattern
2562306a36Sopenharmony_ci * @s: the string to examine for presence of the pattern
2662306a36Sopenharmony_ci * @p: the string containing the pattern
2762306a36Sopenharmony_ci * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
2862306a36Sopenharmony_ci * locations.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * Description: Determines if the pattern @p is present in string @s. Can only
3162306a36Sopenharmony_ci * match extremely simple token=arg style patterns. If the pattern is found,
3262306a36Sopenharmony_ci * the location(s) of the arguments will be returned in the @args array.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistatic int match_one(char *s, const char *p, substring_t args[])
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	char *meta;
3762306a36Sopenharmony_ci	int argc = 0;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (!p)
4062306a36Sopenharmony_ci		return 1;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	while(1) {
4362306a36Sopenharmony_ci		int len = -1;
4462306a36Sopenharmony_ci		meta = strchr(p, '%');
4562306a36Sopenharmony_ci		if (!meta)
4662306a36Sopenharmony_ci			return strcmp(p, s) == 0;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci		if (strncmp(p, s, meta-p))
4962306a36Sopenharmony_ci			return 0;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		s += meta - p;
5262306a36Sopenharmony_ci		p = meta + 1;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		if (isdigit(*p))
5562306a36Sopenharmony_ci			len = simple_strtoul(p, (char **) &p, 10);
5662306a36Sopenharmony_ci		else if (*p == '%') {
5762306a36Sopenharmony_ci			if (*s++ != '%')
5862306a36Sopenharmony_ci				return 0;
5962306a36Sopenharmony_ci			p++;
6062306a36Sopenharmony_ci			continue;
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		if (argc >= MAX_OPT_ARGS)
6462306a36Sopenharmony_ci			return 0;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		args[argc].from = s;
6762306a36Sopenharmony_ci		switch (*p++) {
6862306a36Sopenharmony_ci		case 's': {
6962306a36Sopenharmony_ci			size_t str_len = strlen(s);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci			if (str_len == 0)
7262306a36Sopenharmony_ci				return 0;
7362306a36Sopenharmony_ci			if (len == -1 || len > str_len)
7462306a36Sopenharmony_ci				len = str_len;
7562306a36Sopenharmony_ci			args[argc].to = s + len;
7662306a36Sopenharmony_ci			break;
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci		case 'd':
7962306a36Sopenharmony_ci			simple_strtol(s, &args[argc].to, 0);
8062306a36Sopenharmony_ci			goto num;
8162306a36Sopenharmony_ci		case 'u':
8262306a36Sopenharmony_ci			simple_strtoul(s, &args[argc].to, 0);
8362306a36Sopenharmony_ci			goto num;
8462306a36Sopenharmony_ci		case 'o':
8562306a36Sopenharmony_ci			simple_strtoul(s, &args[argc].to, 8);
8662306a36Sopenharmony_ci			goto num;
8762306a36Sopenharmony_ci		case 'x':
8862306a36Sopenharmony_ci			simple_strtoul(s, &args[argc].to, 16);
8962306a36Sopenharmony_ci		num:
9062306a36Sopenharmony_ci			if (args[argc].to == args[argc].from)
9162306a36Sopenharmony_ci				return 0;
9262306a36Sopenharmony_ci			break;
9362306a36Sopenharmony_ci		default:
9462306a36Sopenharmony_ci			return 0;
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci		s = args[argc].to;
9762306a36Sopenharmony_ci		argc++;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/**
10262306a36Sopenharmony_ci * match_token - Find a token (and optional args) in a string
10362306a36Sopenharmony_ci * @s: the string to examine for token/argument pairs
10462306a36Sopenharmony_ci * @table: match_table_t describing the set of allowed option tokens and the
10562306a36Sopenharmony_ci * arguments that may be associated with them. Must be terminated with a
10662306a36Sopenharmony_ci * &struct match_token whose pattern is set to the NULL pointer.
10762306a36Sopenharmony_ci * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
10862306a36Sopenharmony_ci * locations.
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci * Description: Detects which if any of a set of token strings has been passed
11162306a36Sopenharmony_ci * to it. Tokens can include up to %MAX_OPT_ARGS instances of basic c-style
11262306a36Sopenharmony_ci * format identifiers which will be taken into account when matching the
11362306a36Sopenharmony_ci * tokens, and whose locations will be returned in the @args array.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ciint match_token(char *s, const match_table_t table, substring_t args[])
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	const struct match_token *p;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for (p = table; !match_one(s, p->pattern, args) ; p++)
12062306a36Sopenharmony_ci		;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return p->token;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ciEXPORT_SYMBOL(match_token);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/**
12762306a36Sopenharmony_ci * match_number - scan a number in the given base from a substring_t
12862306a36Sopenharmony_ci * @s: substring to be scanned
12962306a36Sopenharmony_ci * @result: resulting integer on success
13062306a36Sopenharmony_ci * @base: base to use when converting string
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * Description: Given a &substring_t and a base, attempts to parse the substring
13362306a36Sopenharmony_ci * as a number in that base.
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the
13662306a36Sopenharmony_ci * string and returns 0. Returns -EINVAL or -ERANGE on failure.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic int match_number(substring_t *s, int *result, int base)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	char *endp;
14162306a36Sopenharmony_ci	char buf[NUMBER_BUF_LEN];
14262306a36Sopenharmony_ci	int ret;
14362306a36Sopenharmony_ci	long val;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (match_strlcpy(buf, s, NUMBER_BUF_LEN) >= NUMBER_BUF_LEN)
14662306a36Sopenharmony_ci		return -ERANGE;
14762306a36Sopenharmony_ci	ret = 0;
14862306a36Sopenharmony_ci	val = simple_strtol(buf, &endp, base);
14962306a36Sopenharmony_ci	if (endp == buf)
15062306a36Sopenharmony_ci		ret = -EINVAL;
15162306a36Sopenharmony_ci	else if (val < (long)INT_MIN || val > (long)INT_MAX)
15262306a36Sopenharmony_ci		ret = -ERANGE;
15362306a36Sopenharmony_ci	else
15462306a36Sopenharmony_ci		*result = (int) val;
15562306a36Sopenharmony_ci	return ret;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/**
15962306a36Sopenharmony_ci * match_u64int - scan a number in the given base from a substring_t
16062306a36Sopenharmony_ci * @s: substring to be scanned
16162306a36Sopenharmony_ci * @result: resulting u64 on success
16262306a36Sopenharmony_ci * @base: base to use when converting string
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * Description: Given a &substring_t and a base, attempts to parse the substring
16562306a36Sopenharmony_ci * as a number in that base.
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the
16862306a36Sopenharmony_ci * string and returns 0. Returns -EINVAL or -ERANGE on failure.
16962306a36Sopenharmony_ci */
17062306a36Sopenharmony_cistatic int match_u64int(substring_t *s, u64 *result, int base)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	char buf[NUMBER_BUF_LEN];
17362306a36Sopenharmony_ci	int ret;
17462306a36Sopenharmony_ci	u64 val;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (match_strlcpy(buf, s, NUMBER_BUF_LEN) >= NUMBER_BUF_LEN)
17762306a36Sopenharmony_ci		return -ERANGE;
17862306a36Sopenharmony_ci	ret = kstrtoull(buf, base, &val);
17962306a36Sopenharmony_ci	if (!ret)
18062306a36Sopenharmony_ci		*result = val;
18162306a36Sopenharmony_ci	return ret;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/**
18562306a36Sopenharmony_ci * match_int - scan a decimal representation of an integer from a substring_t
18662306a36Sopenharmony_ci * @s: substring_t to be scanned
18762306a36Sopenharmony_ci * @result: resulting integer on success
18862306a36Sopenharmony_ci *
18962306a36Sopenharmony_ci * Description: Attempts to parse the &substring_t @s as a decimal integer.
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the string
19262306a36Sopenharmony_ci * and returns 0. Returns -EINVAL or -ERANGE on failure.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_ciint match_int(substring_t *s, int *result)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	return match_number(s, result, 0);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ciEXPORT_SYMBOL(match_int);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci/**
20162306a36Sopenharmony_ci * match_uint - scan a decimal representation of an integer from a substring_t
20262306a36Sopenharmony_ci * @s: substring_t to be scanned
20362306a36Sopenharmony_ci * @result: resulting integer on success
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * Description: Attempts to parse the &substring_t @s as a decimal integer.
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the string
20862306a36Sopenharmony_ci * and returns 0. Returns -EINVAL or -ERANGE on failure.
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciint match_uint(substring_t *s, unsigned int *result)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	char buf[NUMBER_BUF_LEN];
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (match_strlcpy(buf, s, NUMBER_BUF_LEN) >= NUMBER_BUF_LEN)
21562306a36Sopenharmony_ci		return -ERANGE;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return kstrtouint(buf, 10, result);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ciEXPORT_SYMBOL(match_uint);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/**
22262306a36Sopenharmony_ci * match_u64 - scan a decimal representation of a u64 from
22362306a36Sopenharmony_ci *                  a substring_t
22462306a36Sopenharmony_ci * @s: substring_t to be scanned
22562306a36Sopenharmony_ci * @result: resulting unsigned long long on success
22662306a36Sopenharmony_ci *
22762306a36Sopenharmony_ci * Description: Attempts to parse the &substring_t @s as a long decimal
22862306a36Sopenharmony_ci * integer.
22962306a36Sopenharmony_ci *
23062306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the string
23162306a36Sopenharmony_ci * and returns 0. Returns -EINVAL or -ERANGE on failure.
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_ciint match_u64(substring_t *s, u64 *result)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	return match_u64int(s, result, 0);
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ciEXPORT_SYMBOL(match_u64);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/**
24062306a36Sopenharmony_ci * match_octal - scan an octal representation of an integer from a substring_t
24162306a36Sopenharmony_ci * @s: substring_t to be scanned
24262306a36Sopenharmony_ci * @result: resulting integer on success
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * Description: Attempts to parse the &substring_t @s as an octal integer.
24562306a36Sopenharmony_ci *
24662306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the string
24762306a36Sopenharmony_ci * and returns 0. Returns -EINVAL or -ERANGE on failure.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_ciint match_octal(substring_t *s, int *result)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return match_number(s, result, 8);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ciEXPORT_SYMBOL(match_octal);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/**
25662306a36Sopenharmony_ci * match_hex - scan a hex representation of an integer from a substring_t
25762306a36Sopenharmony_ci * @s: substring_t to be scanned
25862306a36Sopenharmony_ci * @result: resulting integer on success
25962306a36Sopenharmony_ci *
26062306a36Sopenharmony_ci * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Return: On success, sets @result to the integer represented by the string
26362306a36Sopenharmony_ci * and returns 0. Returns -EINVAL or -ERANGE on failure.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_ciint match_hex(substring_t *s, int *result)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return match_number(s, result, 16);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ciEXPORT_SYMBOL(match_hex);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/**
27262306a36Sopenharmony_ci * match_wildcard - parse if a string matches given wildcard pattern
27362306a36Sopenharmony_ci * @pattern: wildcard pattern
27462306a36Sopenharmony_ci * @str: the string to be parsed
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * Description: Parse the string @str to check if matches wildcard
27762306a36Sopenharmony_ci * pattern @pattern. The pattern may contain two types of wildcards:
27862306a36Sopenharmony_ci *   '*' - matches zero or more characters
27962306a36Sopenharmony_ci *   '?' - matches one character
28062306a36Sopenharmony_ci *
28162306a36Sopenharmony_ci * Return: If the @str matches the @pattern, return true, else return false.
28262306a36Sopenharmony_ci */
28362306a36Sopenharmony_cibool match_wildcard(const char *pattern, const char *str)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	const char *s = str;
28662306a36Sopenharmony_ci	const char *p = pattern;
28762306a36Sopenharmony_ci	bool star = false;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	while (*s) {
29062306a36Sopenharmony_ci		switch (*p) {
29162306a36Sopenharmony_ci		case '?':
29262306a36Sopenharmony_ci			s++;
29362306a36Sopenharmony_ci			p++;
29462306a36Sopenharmony_ci			break;
29562306a36Sopenharmony_ci		case '*':
29662306a36Sopenharmony_ci			star = true;
29762306a36Sopenharmony_ci			str = s;
29862306a36Sopenharmony_ci			if (!*++p)
29962306a36Sopenharmony_ci				return true;
30062306a36Sopenharmony_ci			pattern = p;
30162306a36Sopenharmony_ci			break;
30262306a36Sopenharmony_ci		default:
30362306a36Sopenharmony_ci			if (*s == *p) {
30462306a36Sopenharmony_ci				s++;
30562306a36Sopenharmony_ci				p++;
30662306a36Sopenharmony_ci			} else {
30762306a36Sopenharmony_ci				if (!star)
30862306a36Sopenharmony_ci					return false;
30962306a36Sopenharmony_ci				str++;
31062306a36Sopenharmony_ci				s = str;
31162306a36Sopenharmony_ci				p = pattern;
31262306a36Sopenharmony_ci			}
31362306a36Sopenharmony_ci			break;
31462306a36Sopenharmony_ci		}
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (*p == '*')
31862306a36Sopenharmony_ci		++p;
31962306a36Sopenharmony_ci	return !*p;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ciEXPORT_SYMBOL(match_wildcard);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci/**
32462306a36Sopenharmony_ci * match_strlcpy - Copy the characters from a substring_t to a sized buffer
32562306a36Sopenharmony_ci * @dest: where to copy to
32662306a36Sopenharmony_ci * @src: &substring_t to copy
32762306a36Sopenharmony_ci * @size: size of destination buffer
32862306a36Sopenharmony_ci *
32962306a36Sopenharmony_ci * Description: Copy the characters in &substring_t @src to the
33062306a36Sopenharmony_ci * c-style string @dest.  Copy no more than @size - 1 characters, plus
33162306a36Sopenharmony_ci * the terminating NUL.
33262306a36Sopenharmony_ci *
33362306a36Sopenharmony_ci * Return: length of @src.
33462306a36Sopenharmony_ci */
33562306a36Sopenharmony_cisize_t match_strlcpy(char *dest, const substring_t *src, size_t size)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	size_t ret = src->to - src->from;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (size) {
34062306a36Sopenharmony_ci		size_t len = ret >= size ? size - 1 : ret;
34162306a36Sopenharmony_ci		memcpy(dest, src->from, len);
34262306a36Sopenharmony_ci		dest[len] = '\0';
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	return ret;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ciEXPORT_SYMBOL(match_strlcpy);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * match_strdup - allocate a new string with the contents of a substring_t
35062306a36Sopenharmony_ci * @s: &substring_t to copy
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * Description: Allocates and returns a string filled with the contents of
35362306a36Sopenharmony_ci * the &substring_t @s. The caller is responsible for freeing the returned
35462306a36Sopenharmony_ci * string with kfree().
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci * Return: the address of the newly allocated NUL-terminated string or
35762306a36Sopenharmony_ci * %NULL on error.
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_cichar *match_strdup(const substring_t *s)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	return kmemdup_nul(s->from, s->to - s->from, GFP_KERNEL);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ciEXPORT_SYMBOL(match_strdup);
364