Branch data Line data Source code
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 : : */ 24 : 3 : static int match_one(char *s, const char *p, substring_t args[]) 25 : : { 26 : : char *meta; 27 : : int argc = 0; 28 : : 29 : 3 : if (!p) 30 : : return 1; 31 : : 32 : : while(1) { 33 : : int len = -1; 34 : 3 : meta = strchr(p, '%'); 35 : 3 : if (!meta) 36 : 3 : return strcmp(p, s) == 0; 37 : : 38 : 3 : if (strncmp(p, s, meta-p)) 39 : : return 0; 40 : : 41 : 3 : s += meta - p; 42 : 3 : p = meta + 1; 43 : : 44 : 3 : if (isdigit(*p)) 45 : 0 : len = simple_strtoul(p, (char **) &p, 10); 46 : 3 : else if (*p == '%') { 47 : 0 : if (*s++ != '%') 48 : : return 0; 49 : 0 : p++; 50 : 0 : continue; 51 : : } 52 : : 53 : 3 : if (argc >= MAX_OPT_ARGS) 54 : : return 0; 55 : : 56 : 3 : args[argc].from = s; 57 : 3 : switch (*p++) { 58 : : case 's': { 59 : 0 : size_t str_len = strlen(s); 60 : : 61 : 0 : if (str_len == 0) 62 : : return 0; 63 : 0 : if (len == -1 || len > str_len) 64 : 0 : len = str_len; 65 : 0 : args[argc].to = s + len; 66 : 0 : break; 67 : : } 68 : : case 'd': 69 : 0 : simple_strtol(s, &args[argc].to, 0); 70 : 0 : goto num; 71 : : case 'u': 72 : 3 : simple_strtoul(s, &args[argc].to, 0); 73 : 3 : goto num; 74 : : case 'o': 75 : 3 : simple_strtoul(s, &args[argc].to, 8); 76 : 3 : goto num; 77 : : case 'x': 78 : 0 : simple_strtoul(s, &args[argc].to, 16); 79 : : num: 80 : 3 : if (args[argc].to == args[argc].from) 81 : : return 0; 82 : : break; 83 : : default: 84 : : return 0; 85 : : } 86 : 3 : s = args[argc].to; 87 : 3 : 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 : : */ 105 : 3 : int match_token(char *s, const match_table_t table, substring_t args[]) 106 : : { 107 : : const struct match_token *p; 108 : : 109 : 3 : for (p = table; !match_one(s, p->pattern, args) ; p++) 110 : : ; 111 : : 112 : 3 : 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 : : */ 126 : 3 : 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 : 3 : if (!buf) 135 : : return -ENOMEM; 136 : : 137 : : ret = 0; 138 : 3 : val = simple_strtol(buf, &endp, base); 139 : 3 : if (endp == buf) 140 : : ret = -EINVAL; 141 : : else if (val < (long)INT_MIN || val > (long)INT_MAX) 142 : : ret = -ERANGE; 143 : : else 144 : 3 : *result = (int) val; 145 : 3 : kfree(buf); 146 : 3 : 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 : : */ 159 : 0 : 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 : 0 : if (!buf) 167 : : return -ENOMEM; 168 : : 169 : 0 : ret = kstrtoull(buf, base, &val); 170 : 0 : if (!ret) 171 : 0 : *result = val; 172 : 0 : kfree(buf); 173 : 0 : 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 : : */ 185 : 3 : int match_int(substring_t *s, int *result) 186 : : { 187 : 3 : 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 : : */ 202 : 0 : int match_u64(substring_t *s, u64 *result) 203 : : { 204 : 0 : 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 : : */ 217 : 3 : int match_octal(substring_t *s, int *result) 218 : : { 219 : 3 : 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 : : */ 232 : 0 : int match_hex(substring_t *s, int *result) 233 : : { 234 : 0 : 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 : : */ 249 : 0 : 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 : 0 : while (*s) { 256 : 0 : switch (*p) { 257 : : case '?': 258 : 0 : s++; 259 : 0 : p++; 260 : 0 : break; 261 : : case '*': 262 : : star = true; 263 : : str = s; 264 : 0 : if (!*++p) 265 : : return true; 266 : : pattern = p; 267 : : break; 268 : : default: 269 : 0 : if (*s == *p) { 270 : 0 : s++; 271 : 0 : p++; 272 : : } else { 273 : 0 : if (!star) 274 : : return false; 275 : 0 : str++; 276 : : s = str; 277 : : p = pattern; 278 : : } 279 : : break; 280 : : } 281 : : } 282 : : 283 : 0 : if (*p == '*') 284 : 0 : ++p; 285 : 0 : 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 : : */ 299 : 0 : size_t match_strlcpy(char *dest, const substring_t *src, size_t size) 300 : : { 301 : 0 : size_t ret = src->to - src->from; 302 : : 303 : 0 : if (size) { 304 : 0 : size_t len = ret >= size ? size - 1 : ret; 305 : 0 : memcpy(dest, src->from, len); 306 : 0 : dest[len] = '\0'; 307 : : } 308 : 0 : 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 : : */ 320 : 0 : char *match_strdup(const substring_t *s) 321 : : { 322 : 3 : return kmemdup_nul(s->from, s->to - s->from, GFP_KERNEL); 323 : : } 324 : : EXPORT_SYMBOL(match_strdup);