2019-06-03 08:44:46 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-17 02:20:36 +04:00
/*
* lib / parser . c - simple parser for mount , etc . options .
*/
# include <linux/ctype.h>
2011-11-17 06:29:17 +04:00
# include <linux/types.h>
# include <linux/export.h>
2021-07-01 04:56:10 +03:00
# include <linux/kstrtox.h>
2005-04-17 02:20:36 +04:00
# include <linux/parser.h>
# include <linux/slab.h>
# include <linux/string.h>
/**
2021-01-29 08:00:37 +03:00
* match_one - Determines if a string matches a simple pattern
2011-03-31 05:57:33 +04:00
* @ s : the string to examine for presence of the pattern
2005-04-17 02:20:36 +04:00
* @ p : the string containing the pattern
* @ args : array of % MAX_OPT_ARGS & substring_t elements . Used to return match
* locations .
*
* Description : Determines if the pattern @ p is present in string @ s . Can only
* match extremely simple token = arg style patterns . If the pattern is found ,
* the location ( s ) of the arguments will be returned in the @ args array .
*/
2007-05-03 14:10:39 +04:00
static int match_one ( char * s , const char * p , substring_t args [ ] )
2005-04-17 02:20:36 +04:00
{
char * meta ;
int argc = 0 ;
if ( ! p )
return 1 ;
while ( 1 ) {
int len = - 1 ;
meta = strchr ( p , ' % ' ) ;
if ( ! meta )
return strcmp ( p , s ) = = 0 ;
if ( strncmp ( p , s , meta - p ) )
return 0 ;
s + = meta - p ;
p = meta + 1 ;
if ( isdigit ( * p ) )
2007-05-03 14:10:39 +04:00
len = simple_strtoul ( p , ( char * * ) & p , 10 ) ;
2005-04-17 02:20:36 +04:00
else if ( * p = = ' % ' ) {
if ( * s + + ! = ' % ' )
return 0 ;
p + + ;
continue ;
}
if ( argc > = MAX_OPT_ARGS )
return 0 ;
args [ argc ] . from = s ;
switch ( * p + + ) {
2009-12-15 05:01:08 +03:00
case ' s ' : {
size_t str_len = strlen ( s ) ;
if ( str_len = = 0 )
2005-04-17 02:20:36 +04:00
return 0 ;
2009-12-15 05:01:08 +03:00
if ( len = = - 1 | | len > str_len )
len = str_len ;
2005-04-17 02:20:36 +04:00
args [ argc ] . to = s + len ;
break ;
2009-12-15 05:01:08 +03:00
}
2005-04-17 02:20:36 +04:00
case ' d ' :
simple_strtol ( s , & args [ argc ] . to , 0 ) ;
goto num ;
case ' u ' :
simple_strtoul ( s , & args [ argc ] . to , 0 ) ;
goto num ;
case ' o ' :
simple_strtoul ( s , & args [ argc ] . to , 8 ) ;
goto num ;
case ' x ' :
simple_strtoul ( s , & args [ argc ] . to , 16 ) ;
num :
if ( args [ argc ] . to = = args [ argc ] . from )
return 0 ;
break ;
default :
return 0 ;
}
s = args [ argc ] . to ;
argc + + ;
}
}
/**
2021-01-29 08:00:37 +03:00
* match_token - Find a token ( and optional args ) in a string
2005-04-17 02:20:36 +04:00
* @ s : the string to examine for token / argument pairs
* @ table : match_table_t describing the set of allowed option tokens and the
* arguments that may be associated with them . Must be terminated with a
* & struct match_token whose pattern is set to the NULL pointer .
* @ args : array of % MAX_OPT_ARGS & substring_t elements . Used to return match
* locations .
*
* Description : Detects which if any of a set of token strings has been passed
2021-05-07 04:03:49 +03:00
* to it . Tokens can include up to % MAX_OPT_ARGS instances of basic c - style
2005-04-17 02:20:36 +04:00
* format identifiers which will be taken into account when matching the
* tokens , and whose locations will be returned in the @ args array .
*/
2008-10-13 13:46:57 +04:00
int match_token ( char * s , const match_table_t table , substring_t args [ ] )
2005-04-17 02:20:36 +04:00
{
2007-05-03 14:10:39 +04:00
const struct match_token * p ;
2005-04-17 02:20:36 +04:00
for ( p = table ; ! match_one ( s , p - > pattern , args ) ; p + + )
;
return p - > token ;
}
2014-01-24 03:54:13 +04:00
EXPORT_SYMBOL ( match_token ) ;
2005-04-17 02:20:36 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_number - scan a number in the given base from a substring_t
2005-04-17 02:20:36 +04:00
* @ s : substring to be scanned
* @ result : resulting integer on success
* @ base : base to use when converting string
*
* Description : Given a & substring_t and a base , attempts to parse the substring
2021-05-07 04:03:49 +03:00
* as a number in that base .
*
* Return : On success , sets @ result to the integer represented by the
* string and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2005-04-17 02:20:36 +04:00
*/
static int match_number ( substring_t * s , int * result , int base )
{
char * endp ;
char * buf ;
int ret ;
2012-10-05 04:13:16 +04:00
long val ;
2005-04-17 02:20:36 +04:00
2018-10-31 01:05:30 +03:00
buf = match_strdup ( s ) ;
2005-04-17 02:20:36 +04:00
if ( ! buf )
return - ENOMEM ;
2012-10-05 04:13:16 +04:00
2005-04-17 02:20:36 +04:00
ret = 0 ;
2012-10-05 04:13:16 +04:00
val = simple_strtol ( buf , & endp , base ) ;
2005-04-17 02:20:36 +04:00
if ( endp = = buf )
ret = - EINVAL ;
2012-10-05 04:13:16 +04:00
else if ( val < ( long ) INT_MIN | | val > ( long ) INT_MAX )
ret = - ERANGE ;
else
* result = ( int ) val ;
2005-04-17 02:20:36 +04:00
kfree ( buf ) ;
return ret ;
}
2016-10-21 23:51:54 +03:00
/**
2021-01-29 08:00:37 +03:00
* match_u64int - scan a number in the given base from a substring_t
2016-10-21 23:51:54 +03:00
* @ s : substring to be scanned
* @ result : resulting u64 on success
* @ base : base to use when converting string
*
* Description : Given a & substring_t and a base , attempts to parse the substring
2021-05-07 04:03:49 +03:00
* as a number in that base .
*
* Return : On success , sets @ result to the integer represented by the
* string and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2016-10-21 23:51:54 +03:00
*/
static int match_u64int ( substring_t * s , u64 * result , int base )
{
char * buf ;
int ret ;
u64 val ;
2018-10-31 01:05:26 +03:00
buf = match_strdup ( s ) ;
2016-10-21 23:51:54 +03:00
if ( ! buf )
return - ENOMEM ;
ret = kstrtoull ( buf , base , & val ) ;
if ( ! ret )
* result = val ;
kfree ( buf ) ;
return ret ;
}
2005-04-17 02:20:36 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_int - scan a decimal representation of an integer from a substring_t
2005-04-17 02:20:36 +04:00
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
2021-05-07 04:03:49 +03:00
* Description : Attempts to parse the & substring_t @ s as a decimal integer .
*
* Return : On success , sets @ result to the integer represented by the string
* and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2005-04-17 02:20:36 +04:00
*/
int match_int ( substring_t * s , int * result )
{
return match_number ( s , result , 0 ) ;
}
2014-01-24 03:54:13 +04:00
EXPORT_SYMBOL ( match_int ) ;
2005-04-17 02:20:36 +04:00
2021-05-07 04:03:49 +03:00
/**
2021-01-29 07:52:42 +03:00
* match_uint - scan a decimal representation of an integer from a substring_t
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
2021-05-07 04:03:49 +03:00
* Description : Attempts to parse the & substring_t @ s as a decimal integer .
*
* Return : On success , sets @ result to the integer represented by the string
* and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2021-01-29 07:52:42 +03:00
*/
int match_uint ( substring_t * s , unsigned int * result )
{
int err = - ENOMEM ;
char * buf = match_strdup ( s ) ;
if ( buf ) {
err = kstrtouint ( buf , 10 , result ) ;
kfree ( buf ) ;
}
return err ;
}
EXPORT_SYMBOL ( match_uint ) ;
2016-10-21 23:51:54 +03:00
/**
2021-01-29 08:00:37 +03:00
* match_u64 - scan a decimal representation of a u64 from
2016-10-21 23:51:54 +03:00
* a substring_t
* @ s : substring_t to be scanned
* @ result : resulting unsigned long long on success
*
* Description : Attempts to parse the & substring_t @ s as a long decimal
2021-05-07 04:03:49 +03:00
* integer .
*
* Return : On success , sets @ result to the integer represented by the string
* and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2016-10-21 23:51:54 +03:00
*/
int match_u64 ( substring_t * s , u64 * result )
{
return match_u64int ( s , result , 0 ) ;
}
EXPORT_SYMBOL ( match_u64 ) ;
2005-04-17 02:20:36 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_octal - scan an octal representation of an integer from a substring_t
2005-04-17 02:20:36 +04:00
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
2021-05-07 04:03:49 +03:00
* Description : Attempts to parse the & substring_t @ s as an octal integer .
*
* Return : On success , sets @ result to the integer represented by the string
* and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2005-04-17 02:20:36 +04:00
*/
int match_octal ( substring_t * s , int * result )
{
return match_number ( s , result , 8 ) ;
}
2014-01-24 03:54:13 +04:00
EXPORT_SYMBOL ( match_octal ) ;
2005-04-17 02:20:36 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_hex - scan a hex representation of an integer from a substring_t
2005-04-17 02:20:36 +04:00
* @ s : substring_t to be scanned
* @ result : resulting integer on success
*
* Description : Attempts to parse the & substring_t @ s as a hexadecimal integer .
2021-05-07 04:03:49 +03:00
*
* Return : On success , sets @ result to the integer represented by the string
* and returns 0. Returns - ENOMEM , - EINVAL , or - ERANGE on failure .
2005-04-17 02:20:36 +04:00
*/
int match_hex ( substring_t * s , int * result )
{
return match_number ( s , result , 16 ) ;
}
2014-01-24 03:54:13 +04:00
EXPORT_SYMBOL ( match_hex ) ;
2005-04-17 02:20:36 +04:00
2014-01-24 03:54:12 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_wildcard - parse if a string matches given wildcard pattern
2014-01-24 03:54:12 +04:00
* @ pattern : wildcard pattern
* @ str : the string to be parsed
*
* Description : Parse the string @ str to check if matches wildcard
2021-05-07 04:03:49 +03:00
* pattern @ pattern . The pattern may contain two types of wildcards :
2014-01-24 03:54:12 +04:00
* ' * ' - matches zero or more characters
* ' ? ' - matches one character
2021-05-07 04:03:49 +03:00
*
* Return : If the @ str matches the @ pattern , return true , else return false .
2014-01-24 03:54:12 +04:00
*/
bool match_wildcard ( const char * pattern , const char * str )
{
const char * s = str ;
const char * p = pattern ;
bool star = false ;
while ( * s ) {
switch ( * p ) {
case ' ? ' :
s + + ;
p + + ;
break ;
case ' * ' :
star = true ;
str = s ;
if ( ! * + + p )
return true ;
pattern = p ;
break ;
default :
if ( * s = = * p ) {
s + + ;
p + + ;
} else {
if ( ! star )
return false ;
str + + ;
s = str ;
p = pattern ;
}
break ;
}
}
if ( * p = = ' * ' )
+ + p ;
return ! * p ;
}
2014-01-24 03:54:13 +04:00
EXPORT_SYMBOL ( match_wildcard ) ;
2014-01-24 03:54:12 +04:00
2005-04-17 02:20:36 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_strlcpy - Copy the characters from a substring_t to a sized buffer
2008-02-26 18:57:11 +03:00
* @ dest : where to copy to
* @ src : & substring_t to copy
* @ size : size of destination buffer
2005-04-17 02:20:36 +04:00
*
2008-02-26 18:57:11 +03:00
* Description : Copy the characters in & substring_t @ src to the
* c - style string @ dest . Copy no more than @ size - 1 characters , plus
2021-05-07 04:03:49 +03:00
* the terminating NUL .
*
* Return : length of @ src .
2005-04-17 02:20:36 +04:00
*/
2008-02-26 18:57:11 +03:00
size_t match_strlcpy ( char * dest , const substring_t * src , size_t size )
2005-04-17 02:20:36 +04:00
{
2008-02-26 18:57:11 +03:00
size_t ret = src - > to - src - > from ;
if ( size ) {
size_t len = ret > = size ? size - 1 : ret ;
memcpy ( dest , src - > from , len ) ;
dest [ len ] = ' \0 ' ;
}
return ret ;
2005-04-17 02:20:36 +04:00
}
2014-01-24 03:54:13 +04:00
EXPORT_SYMBOL ( match_strlcpy ) ;
2005-04-17 02:20:36 +04:00
/**
2021-01-29 08:00:37 +03:00
* match_strdup - allocate a new string with the contents of a substring_t
2005-04-17 02:20:36 +04:00
* @ s : & substring_t to copy
*
* Description : Allocates and returns a string filled with the contents of
* the & substring_t @ s . The caller is responsible for freeing the returned
* string with kfree ( ) .
2021-05-07 04:03:49 +03:00
*
* Return : the address of the newly allocated NUL - terminated string or
* % NULL on error .
2005-04-17 02:20:36 +04:00
*/
2007-05-03 14:10:39 +04:00
char * match_strdup ( const substring_t * s )
2005-04-17 02:20:36 +04:00
{
2018-10-31 01:05:22 +03:00
return kmemdup_nul ( s - > from , s - > to - s - > from , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( match_strdup ) ;