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