LCOV - code coverage report
Current view: top level - lib - parser.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 59 122 48.4 %
Date: 2021-04-22 12:43:58 Functions: 6 12 50.0 %

          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          29 : static int match_one(char *s, const char *p, substring_t args[])
      25             : {
      26          29 :         char *meta;
      27          29 :         int argc = 0;
      28             : 
      29          29 :         if (!p)
      30             :                 return 1;
      31             : 
      32          37 :         while(1) {
      33          37 :                 int len = -1;
      34          37 :                 meta = strchr(p, '%');
      35          37 :                 if (!meta)
      36          17 :                         return strcmp(p, s) == 0;
      37             : 
      38          20 :                 if (strncmp(p, s, meta-p))
      39             :                         return 0;
      40             : 
      41           8 :                 s += meta - p;
      42           8 :                 p = meta + 1;
      43             : 
      44           8 :                 if (isdigit(*p))
      45           0 :                         len = simple_strtoul(p, (char **) &p, 10);
      46           8 :                 else if (*p == '%') {
      47           0 :                         if (*s++ != '%')
      48             :                                 return 0;
      49           0 :                         p++;
      50           0 :                         continue;
      51             :                 }
      52             : 
      53           8 :                 if (argc >= MAX_OPT_ARGS)
      54             :                         return 0;
      55             : 
      56           8 :                 args[argc].from = s;
      57           8 :                 switch (*p++) {
      58           6 :                 case 's': {
      59           6 :                         size_t str_len = strlen(s);
      60             : 
      61           6 :                         if (str_len == 0)
      62             :                                 return 0;
      63           6 :                         if (len == -1 || len > str_len)
      64           6 :                                 len = str_len;
      65           6 :                         args[argc].to = s + len;
      66           6 :                         break;
      67             :                 }
      68           0 :                 case 'd':
      69           0 :                         simple_strtol(s, &args[argc].to, 0);
      70           0 :                         goto num;
      71           1 :                 case 'u':
      72           1 :                         simple_strtoul(s, &args[argc].to, 0);
      73           1 :                         goto num;
      74           1 :                 case 'o':
      75           1 :                         simple_strtoul(s, &args[argc].to, 8);
      76           1 :                         goto num;
      77           0 :                 case 'x':
      78           0 :                         simple_strtoul(s, &args[argc].to, 16);
      79           2 :                 num:
      80           2 :                         if (args[argc].to == args[argc].from)
      81             :                                 return 0;
      82             :                         break;
      83             :                 default:
      84             :                         return 0;
      85             :                 }
      86           8 :                 s = args[argc].to;
      87           8 :                 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           9 : int match_token(char *s, const match_table_t table, substring_t args[])
     106             : {
     107           9 :         const struct match_token *p;
     108             : 
     109          29 :         for (p = table; !match_one(s, p->pattern, args) ; p++)
     110          20 :                 ;
     111             : 
     112           9 :         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           2 : static int match_number(substring_t *s, int *result, int base)
     127             : {
     128           2 :         char *endp;
     129           2 :         char *buf;
     130           2 :         int ret;
     131           2 :         long val;
     132             : 
     133           2 :         buf = match_strdup(s);
     134           2 :         if (!buf)
     135             :                 return -ENOMEM;
     136             : 
     137           2 :         ret = 0;
     138           2 :         val = simple_strtol(buf, &endp, base);
     139           2 :         if (endp == buf)
     140             :                 ret = -EINVAL;
     141           2 :         else if (val < (long)INT_MIN || val > (long)INT_MAX)
     142             :                 ret = -ERANGE;
     143             :         else
     144           2 :                 *result = (int) val;
     145           2 :         kfree(buf);
     146           2 :         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           0 :         char *buf;
     162           0 :         int ret;
     163           0 :         u64 val;
     164             : 
     165           0 :         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           1 : int match_int(substring_t *s, int *result)
     186             : {
     187           1 :         return match_number(s, result, 0);
     188             : }
     189             : EXPORT_SYMBOL(match_int);
     190             : 
     191             : /*
     192             :  * match_uint - scan a decimal representation of an integer from a substring_t
     193             :  * @s: substring_t to be scanned
     194             :  * @result: resulting integer on success
     195             :  *
     196             :  * Description: Attempts to parse the &substring_t @s as a decimal integer. On
     197             :  * success, sets @result to the integer represented by the string and returns 0.
     198             :  * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
     199             :  */
     200           0 : int match_uint(substring_t *s, unsigned int *result)
     201             : {
     202           0 :         int err = -ENOMEM;
     203           0 :         char *buf = match_strdup(s);
     204             : 
     205           0 :         if (buf) {
     206           0 :                 err = kstrtouint(buf, 10, result);
     207           0 :                 kfree(buf);
     208             :         }
     209           0 :         return err;
     210             : }
     211             : EXPORT_SYMBOL(match_uint);
     212             : 
     213             : /**
     214             :  * match_u64 - scan a decimal representation of a u64 from
     215             :  *                  a substring_t
     216             :  * @s: substring_t to be scanned
     217             :  * @result: resulting unsigned long long on success
     218             :  *
     219             :  * Description: Attempts to parse the &substring_t @s as a long decimal
     220             :  * integer. On success, sets @result to the integer represented by the
     221             :  * string and returns 0.
     222             :  * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
     223             :  */
     224           0 : int match_u64(substring_t *s, u64 *result)
     225             : {
     226           0 :         return match_u64int(s, result, 0);
     227             : }
     228             : EXPORT_SYMBOL(match_u64);
     229             : 
     230             : /**
     231             :  * match_octal - scan an octal representation of an integer from a substring_t
     232             :  * @s: substring_t to be scanned
     233             :  * @result: resulting integer on success
     234             :  *
     235             :  * Description: Attempts to parse the &substring_t @s as an octal integer. On
     236             :  * success, sets @result to the integer represented by the string and returns
     237             :  * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
     238             :  */
     239           1 : int match_octal(substring_t *s, int *result)
     240             : {
     241           1 :         return match_number(s, result, 8);
     242             : }
     243             : EXPORT_SYMBOL(match_octal);
     244             : 
     245             : /**
     246             :  * match_hex - scan a hex representation of an integer from a substring_t
     247             :  * @s: substring_t to be scanned
     248             :  * @result: resulting integer on success
     249             :  *
     250             :  * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
     251             :  * On success, sets @result to the integer represented by the string and
     252             :  * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
     253             :  */
     254           0 : int match_hex(substring_t *s, int *result)
     255             : {
     256           0 :         return match_number(s, result, 16);
     257             : }
     258             : EXPORT_SYMBOL(match_hex);
     259             : 
     260             : /**
     261             :  * match_wildcard - parse if a string matches given wildcard pattern
     262             :  * @pattern: wildcard pattern
     263             :  * @str: the string to be parsed
     264             :  *
     265             :  * Description: Parse the string @str to check if matches wildcard
     266             :  * pattern @pattern. The pattern may contain two type wildcardes:
     267             :  *   '*' - matches zero or more characters
     268             :  *   '?' - matches one character
     269             :  * If it's matched, return true, else return false.
     270             :  */
     271           0 : bool match_wildcard(const char *pattern, const char *str)
     272             : {
     273           0 :         const char *s = str;
     274           0 :         const char *p = pattern;
     275           0 :         bool star = false;
     276             : 
     277           0 :         while (*s) {
     278           0 :                 switch (*p) {
     279           0 :                 case '?':
     280           0 :                         s++;
     281           0 :                         p++;
     282           0 :                         break;
     283           0 :                 case '*':
     284           0 :                         star = true;
     285           0 :                         str = s;
     286           0 :                         if (!*++p)
     287             :                                 return true;
     288             :                         pattern = p;
     289             :                         break;
     290           0 :                 default:
     291           0 :                         if (*s == *p) {
     292           0 :                                 s++;
     293           0 :                                 p++;
     294             :                         } else {
     295           0 :                                 if (!star)
     296             :                                         return false;
     297           0 :                                 str++;
     298           0 :                                 s = str;
     299           0 :                                 p = pattern;
     300             :                         }
     301             :                         break;
     302             :                 }
     303             :         }
     304             : 
     305           0 :         if (*p == '*')
     306           0 :                 ++p;
     307           0 :         return !*p;
     308             : }
     309             : EXPORT_SYMBOL(match_wildcard);
     310             : 
     311             : /**
     312             :  * match_strlcpy - Copy the characters from a substring_t to a sized buffer
     313             :  * @dest: where to copy to
     314             :  * @src: &substring_t to copy
     315             :  * @size: size of destination buffer
     316             :  *
     317             :  * Description: Copy the characters in &substring_t @src to the
     318             :  * c-style string @dest.  Copy no more than @size - 1 characters, plus
     319             :  * the terminating NUL.  Return length of @src.
     320             :  */
     321           0 : size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
     322             : {
     323           0 :         size_t ret = src->to - src->from;
     324             : 
     325           0 :         if (size) {
     326           0 :                 size_t len = ret >= size ? size - 1 : ret;
     327           0 :                 memcpy(dest, src->from, len);
     328           0 :                 dest[len] = '\0';
     329             :         }
     330           0 :         return ret;
     331             : }
     332             : EXPORT_SYMBOL(match_strlcpy);
     333             : 
     334             : /**
     335             :  * match_strdup - allocate a new string with the contents of a substring_t
     336             :  * @s: &substring_t to copy
     337             :  *
     338             :  * Description: Allocates and returns a string filled with the contents of
     339             :  * the &substring_t @s. The caller is responsible for freeing the returned
     340             :  * string with kfree().
     341             :  */
     342           8 : char *match_strdup(const substring_t *s)
     343             : {
     344           8 :         return kmemdup_nul(s->from, s->to - s->from, GFP_KERNEL);
     345             : }
     346             : EXPORT_SYMBOL(match_strdup);

Generated by: LCOV version 1.14