276 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/lib/cmdline.c4 * Helper functions generally used for parsing kernel command line5 * 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 -pcs10 */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 the19 * range of numbers, M-N. This will expand the range and insert20 * 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 string37 * @str: option string38 * @pint: (optional output) integer value parsed from @str39 *40 * Read an int from an option string; if available accept a subsequent41 * comma as well.42 *43 * When @pint is NULL the function can be used as a validator of44 * the current option in the string.45 *46 * Return values:47 * 0 - no int in string48 * 1 - int found, no subsequent comma49 * 2 - int found including a subsequent comma50 * 3 - hyphen found to denote a range51 *52 * Leading hyphen without integer is no integer case, but we consume it53 * 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 else66 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 integers84 * @str: String to be parsed85 * @nints: size of integer array86 * @ints: integer array (must have room for at least one element)87 *88 * This function parses a string containing a comma-separated89 * list of integers, a hyphen-separated range of _positive_ integers,90 * or a combination of both. The parse halts when the array is91 * full, or when no more numbers can be retrieved from the92 * string.93 *94 * When @nints is 0, the function just validates the given @str and95 * returns the amount of parseable integers as described below.96 *97 * Returns:98 *99 * The first element is filled by the number of collected integers100 * in the range. The rest is what was parsed from the @str.101 *102 * Return value is the character in the string which caused103 * the parse to end (typically a null terminator, if @str is104 * 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 the127 * last number in the range. The next iteration128 * will handle the upper number in the range129 */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 number143 * @ptr: Where parse begins144 * @retptr: (output) Optional pointer to next char after parse completes145 *146 * Parses a string into a number. The number stored at @ptr is147 * 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 not195 * @str: String to be parsed196 * @option: option name197 *198 * This function parses a string containing a comma-separated list of199 * 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 && i > 0 && args[i-1] == '"')264 args[i-1] = '\0';265 266 if (args[i]) {267 args[i] = '\0';268 args += i + 1;269 } else270 args += i;271 272 /* Chew up trailing spaces. */273 return skip_spaces(args);274}275EXPORT_SYMBOL(next_arg);276