linux/lib/cmdline.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/lib/cmdline.c
   4 * Helper functions generally used for parsing kernel command line
   5 * and module options.
   6 *
   7 * Code and copyrights come from init/main.c and arch/i386/kernel/setup.c.
   8 *
   9 * GNU Indent formatting options for this file: -kr -i8 -npsl -pcs
  10 */
  11
  12#include <linux/export.h>
  13#include <linux/kernel.h>
  14#include <linux/string.h>
  15#include <linux/ctype.h>
  16
  17/*
  18 *      If a hyphen was found in get_option, this will handle the
  19 *      range of numbers, M-N.  This will expand the range and insert
  20 *      the values[M, M+1, ..., N] into the ints array in get_options.
  21 */
  22
  23static int get_range(char **str, int *pint, int n)
  24{
  25        int x, inc_counter, upper_range;
  26
  27        (*str)++;
  28        upper_range = simple_strtol((*str), NULL, 0);
  29        inc_counter = upper_range - *pint;
  30        for (x = *pint; n && x < upper_range; x++, n--)
  31                *pint++ = x;
  32        return inc_counter;
  33}
  34
  35/**
  36 *      get_option - Parse integer from an option string
  37 *      @str: option string
  38 *      @pint: (optional output) integer value parsed from @str
  39 *
  40 *      Read an int from an option string; if available accept a subsequent
  41 *      comma as well.
  42 *
  43 *      When @pint is NULL the function can be used as a validator of
  44 *      the current option in the string.
  45 *
  46 *      Return values:
  47 *      0 - no int in string
  48 *      1 - int found, no subsequent comma
  49 *      2 - int found including a subsequent comma
  50 *      3 - hyphen found to denote a range
  51 *
  52 *      Leading hyphen without integer is no integer case, but we consume it
  53 *      for the sake of simplification.
  54 */
  55
  56int get_option(char **str, int *pint)
  57{
  58        char *cur = *str;
  59        int value;
  60
  61        if (!cur || !(*cur))
  62                return 0;
  63        if (*cur == '-')
  64                value = -simple_strtoull(++cur, str, 0);
  65        else
  66                value = simple_strtoull(cur, str, 0);
  67        if (pint)
  68                *pint = value;
  69        if (cur == *str)
  70                return 0;
  71        if (**str == ',') {
  72                (*str)++;
  73                return 2;
  74        }
  75        if (**str == '-')
  76                return 3;
  77
  78        return 1;
  79}
  80EXPORT_SYMBOL(get_option);
  81
  82/**
  83 *      get_options - Parse a string into a list of integers
  84 *      @str: String to be parsed
  85 *      @nints: size of integer array
  86 *      @ints: integer array (must have room for at least one element)
  87 *
  88 *      This function parses a string containing a comma-separated
  89 *      list of integers, a hyphen-separated range of _positive_ integers,
  90 *      or a combination of both.  The parse halts when the array is
  91 *      full, or when no more numbers can be retrieved from the
  92 *      string.
  93 *
  94 *      When @nints is 0, the function just validates the given @str and
  95 *      returns the amount of parseable integers as described below.
  96 *
  97 *      Returns:
  98 *
  99 *      The first element is filled by the number of collected integers
 100 *      in the range. The rest is what was parsed from the @str.
 101 *
 102 *      Return value is the character in the string which caused
 103 *      the parse to end (typically a null terminator, if @str is
 104 *      completely parseable).
 105 */
 106
 107char *get_options(const char *str, int nints, int *ints)
 108{
 109        bool validate = (nints == 0);
 110        int res, i = 1;
 111
 112        while (i < nints || validate) {
 113                int *pint = validate ? ints : ints + i;
 114
 115                res = get_option((char **)&str, pint);
 116                if (res == 0)
 117                        break;
 118                if (res == 3) {
 119                        int n = validate ? 0 : nints - i;
 120                        int range_nums;
 121
 122                        range_nums = get_range((char **)&str, pint, n);
 123                        if (range_nums < 0)
 124                                break;
 125                        /*
 126                         * Decrement the result by one to leave out the
 127                         * last number in the range.  The next iteration
 128                         * will handle the upper number in the range
 129                         */
 130                        i += (range_nums - 1);
 131                }
 132                i++;
 133                if (res == 1)
 134                        break;
 135        }
 136        ints[0] = i - 1;
 137        return (char *)str;
 138}
 139EXPORT_SYMBOL(get_options);
 140
 141/**
 142 *      memparse - parse a string with mem suffixes into a number
 143 *      @ptr: Where parse begins
 144 *      @retptr: (output) Optional pointer to next char after parse completes
 145 *
 146 *      Parses a string into a number.  The number stored at @ptr is
 147 *      potentially suffixed with K, M, G, T, P, E.
 148 */
 149
 150unsigned long long memparse(const char *ptr, char **retptr)
 151{
 152        char *endptr;   /* local pointer to end of parsed string */
 153
 154        unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
 155
 156        switch (*endptr) {
 157        case 'E':
 158        case 'e':
 159                ret <<= 10;
 160                fallthrough;
 161        case 'P':
 162        case 'p':
 163                ret <<= 10;
 164                fallthrough;
 165        case 'T':
 166        case 't':
 167                ret <<= 10;
 168                fallthrough;
 169        case 'G':
 170        case 'g':
 171                ret <<= 10;
 172                fallthrough;
 173        case 'M':
 174        case 'm':
 175                ret <<= 10;
 176                fallthrough;
 177        case 'K':
 178        case 'k':
 179                ret <<= 10;
 180                endptr++;
 181                fallthrough;
 182        default:
 183                break;
 184        }
 185
 186        if (retptr)
 187                *retptr = endptr;
 188
 189        return ret;
 190}
 191EXPORT_SYMBOL(memparse);
 192
 193/**
 194 *      parse_option_str - Parse a string and check an option is set or not
 195 *      @str: String to be parsed
 196 *      @option: option name
 197 *
 198 *      This function parses a string containing a comma-separated list of
 199 *      strings like a=b,c.
 200 *
 201 *      Return true if there's such option in the string, or return false.
 202 */
 203bool parse_option_str(const char *str, const char *option)
 204{
 205        while (*str) {
 206                if (!strncmp(str, option, strlen(option))) {
 207                        str += strlen(option);
 208                        if (!*str || *str == ',')
 209                                return true;
 210                }
 211
 212                while (*str && *str != ',')
 213                        str++;
 214
 215                if (*str == ',')
 216                        str++;
 217        }
 218
 219        return false;
 220}
 221
 222/*
 223 * Parse a string to get a param value pair.
 224 * You can use " around spaces, but can't escape ".
 225 * Hyphens and underscores equivalent in parameter names.
 226 */
 227char *next_arg(char *args, char **param, char **val)
 228{
 229        unsigned int i, equals = 0;
 230        int in_quote = 0, quoted = 0;
 231
 232        if (*args == '"') {
 233                args++;
 234                in_quote = 1;
 235                quoted = 1;
 236        }
 237
 238        for (i = 0; args[i]; i++) {
 239                if (isspace(args[i]) && !in_quote)
 240                        break;
 241                if (equals == 0) {
 242                        if (args[i] == '=')
 243                                equals = i;
 244                }
 245                if (args[i] == '"')
 246                        in_quote = !in_quote;
 247        }
 248
 249        *param = args;
 250        if (!equals)
 251                *val = NULL;
 252        else {
 253                args[equals] = '\0';
 254                *val = args + equals + 1;
 255
 256                /* Don't include quotes in value. */
 257                if (**val == '"') {
 258                        (*val)++;
 259                        if (args[i-1] == '"')
 260                                args[i-1] = '\0';
 261                }
 262        }
 263        if (quoted && args[i-1] == '"')
 264                args[i-1] = '\0';
 265
 266        if (args[i]) {
 267                args[i] = '\0';
 268                args += i + 1;
 269        } else
 270                args += i;
 271
 272        /* Chew up trailing spaces. */
 273        return skip_spaces(args);
 274}
 275EXPORT_SYMBOL(next_arg);
 276