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