Line data Source code
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 :
23 0 : static int get_range(char **str, int *pint, int n)
24 : {
25 : int x, inc_counter, upper_range;
26 :
27 0 : (*str)++;
28 0 : upper_range = simple_strtol((*str), NULL, 0);
29 0 : inc_counter = upper_range - *pint;
30 0 : for (x = *pint; n && x < upper_range; x++, n--)
31 0 : *pint++ = x;
32 0 : 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 :
56 0 : int get_option(char **str, int *pint)
57 : {
58 0 : char *cur = *str;
59 : int value;
60 :
61 0 : if (!cur || !(*cur))
62 : return 0;
63 0 : if (*cur == '-')
64 0 : value = -simple_strtoull(++cur, str, 0);
65 : else
66 0 : value = simple_strtoull(cur, str, 0);
67 0 : if (pint)
68 0 : *pint = value;
69 0 : if (cur == *str)
70 : return 0;
71 0 : if (**str == ',') {
72 0 : (*str)++;
73 0 : return 2;
74 : }
75 0 : if (**str == '-')
76 : return 3;
77 :
78 0 : return 1;
79 : }
80 : EXPORT_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 :
107 0 : char *get_options(const char *str, int nints, int *ints)
108 : {
109 0 : bool validate = (nints == 0);
110 0 : int res, i = 1;
111 :
112 0 : while (i < nints || validate) {
113 0 : int *pint = validate ? ints : ints + i;
114 :
115 0 : res = get_option((char **)&str, pint);
116 0 : if (res == 0)
117 : break;
118 0 : if (res == 3) {
119 0 : int n = validate ? 0 : nints - i;
120 : int range_nums;
121 :
122 0 : range_nums = get_range((char **)&str, pint, n);
123 0 : 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 0 : i += (range_nums - 1);
131 : }
132 0 : i++;
133 0 : if (res == 1)
134 : break;
135 : }
136 0 : ints[0] = i - 1;
137 0 : return (char *)str;
138 : }
139 : EXPORT_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 :
150 5 : unsigned long long memparse(const char *ptr, char **retptr)
151 : {
152 : char *endptr; /* local pointer to end of parsed string */
153 :
154 5 : unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
155 :
156 5 : switch (*endptr) {
157 : case 'E':
158 : case 'e':
159 0 : ret <<= 10;
160 : fallthrough;
161 : case 'P':
162 : case 'p':
163 0 : ret <<= 10;
164 : fallthrough;
165 : case 'T':
166 : case 't':
167 0 : ret <<= 10;
168 : fallthrough;
169 : case 'G':
170 : case 'g':
171 5 : ret <<= 10;
172 : fallthrough;
173 : case 'M':
174 : case 'm':
175 5 : ret <<= 10;
176 : fallthrough;
177 : case 'K':
178 : case 'k':
179 5 : ret <<= 10;
180 5 : endptr++;
181 : fallthrough;
182 : default:
183 : break;
184 : }
185 :
186 5 : if (retptr)
187 5 : *retptr = endptr;
188 :
189 5 : return ret;
190 : }
191 : EXPORT_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 : */
203 45 : bool parse_option_str(const char *str, const char *option)
204 : {
205 90 : while (*str) {
206 0 : if (!strncmp(str, option, strlen(option))) {
207 0 : str += strlen(option);
208 0 : if (!*str || *str == ',')
209 : return true;
210 : }
211 :
212 0 : while (*str && *str != ',')
213 0 : str++;
214 :
215 0 : if (*str == ',')
216 0 : 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 : */
227 50 : char *next_arg(char *args, char **param, char **val)
228 : {
229 50 : unsigned int i, equals = 0;
230 50 : int in_quote = 0, quoted = 0;
231 :
232 50 : if (*args == '"') {
233 0 : args++;
234 0 : in_quote = 1;
235 0 : quoted = 1;
236 : }
237 :
238 640 : for (i = 0; args[i]; i++) {
239 630 : if (isspace(args[i]) && !in_quote)
240 : break;
241 590 : if (equals == 0) {
242 450 : if (args[i] == '=')
243 50 : equals = i;
244 : }
245 590 : if (args[i] == '"')
246 0 : in_quote = !in_quote;
247 : }
248 :
249 50 : *param = args;
250 50 : if (!equals)
251 0 : *val = NULL;
252 : else {
253 50 : args[equals] = '\0';
254 50 : *val = args + equals + 1;
255 :
256 : /* Don't include quotes in value. */
257 50 : if (**val == '"') {
258 0 : (*val)++;
259 0 : if (args[i-1] == '"')
260 0 : args[i-1] = '\0';
261 : }
262 : }
263 50 : if (quoted && i > 0 && args[i-1] == '"')
264 0 : args[i-1] = '\0';
265 :
266 50 : if (args[i]) {
267 40 : args[i] = '\0';
268 40 : args += i + 1;
269 : } else
270 : args += i;
271 :
272 : /* Chew up trailing spaces. */
273 50 : return skip_spaces(args);
274 : }
275 : EXPORT_SYMBOL(next_arg);
|