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