Branch data 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: (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 : : * Return values:
44 : : * 0 - no int in string
45 : : * 1 - int found, no subsequent comma
46 : : * 2 - int found including a subsequent comma
47 : : * 3 - hyphen found to denote a range
48 : : */
49 : :
50 : 0 : int get_option(char **str, int *pint)
51 : : {
52 : 0 : char *cur = *str;
53 : :
54 [ # # # # ]: 0 : if (!cur || !(*cur))
55 : : return 0;
56 : 0 : *pint = simple_strtol(cur, str, 0);
57 [ # # ]: 0 : if (cur == *str)
58 : : return 0;
59 [ # # ]: 0 : if (**str == ',') {
60 : 0 : (*str)++;
61 : 0 : return 2;
62 : : }
63 [ # # ]: 0 : if (**str == '-')
64 : : return 3;
65 : :
66 : 0 : return 1;
67 : : }
68 : : EXPORT_SYMBOL(get_option);
69 : :
70 : : /**
71 : : * get_options - Parse a string into a list of integers
72 : : * @str: String to be parsed
73 : : * @nints: size of integer array
74 : : * @ints: integer array
75 : : *
76 : : * This function parses a string containing a comma-separated
77 : : * list of integers, a hyphen-separated range of _positive_ integers,
78 : : * or a combination of both. The parse halts when the array is
79 : : * full, or when no more numbers can be retrieved from the
80 : : * string.
81 : : *
82 : : * Return value is the character in the string which caused
83 : : * the parse to end (typically a null terminator, if @str is
84 : : * completely parseable).
85 : : */
86 : :
87 : 0 : char *get_options(const char *str, int nints, int *ints)
88 : : {
89 : : int res, i = 1;
90 : :
91 [ # # ]: 0 : while (i < nints) {
92 : 0 : res = get_option((char **)&str, ints + i);
93 [ # # ]: 0 : if (res == 0)
94 : : break;
95 [ # # ]: 0 : if (res == 3) {
96 : : int range_nums;
97 : 0 : range_nums = get_range((char **)&str, ints + i, nints - i);
98 [ # # ]: 0 : if (range_nums < 0)
99 : : break;
100 : : /*
101 : : * Decrement the result by one to leave out the
102 : : * last number in the range. The next iteration
103 : : * will handle the upper number in the range
104 : : */
105 : 0 : i += (range_nums - 1);
106 : : }
107 : 0 : i++;
108 [ # # ]: 0 : if (res == 1)
109 : : break;
110 : : }
111 : 0 : ints[0] = i - 1;
112 : 0 : return (char *)str;
113 : : }
114 : : EXPORT_SYMBOL(get_options);
115 : :
116 : : /**
117 : : * memparse - parse a string with mem suffixes into a number
118 : : * @ptr: Where parse begins
119 : : * @retptr: (output) Optional pointer to next char after parse completes
120 : : *
121 : : * Parses a string into a number. The number stored at @ptr is
122 : : * potentially suffixed with K, M, G, T, P, E.
123 : : */
124 : :
125 : 621 : unsigned long long memparse(const char *ptr, char **retptr)
126 : : {
127 : : char *endptr; /* local pointer to end of parsed string */
128 : :
129 : 621 : unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
130 : :
131 [ - - - - : 621 : switch (*endptr) {
+ - + ]
132 : : case 'E':
133 : : case 'e':
134 : 0 : ret <<= 10;
135 : : /* fall through */
136 : : case 'P':
137 : : case 'p':
138 : 0 : ret <<= 10;
139 : : /* fall through */
140 : : case 'T':
141 : : case 't':
142 : 0 : ret <<= 10;
143 : : /* fall through */
144 : : case 'G':
145 : : case 'g':
146 : 0 : ret <<= 10;
147 : : /* fall through */
148 : : case 'M':
149 : : case 'm':
150 : 207 : ret <<= 10;
151 : : /* fall through */
152 : : case 'K':
153 : : case 'k':
154 : 207 : ret <<= 10;
155 : 207 : endptr++;
156 : : default:
157 : : break;
158 : : }
159 : :
160 [ + - ]: 621 : if (retptr)
161 : 621 : *retptr = endptr;
162 : :
163 : 621 : return ret;
164 : : }
165 : : EXPORT_SYMBOL(memparse);
166 : :
167 : : /**
168 : : * parse_option_str - Parse a string and check an option is set or not
169 : : * @str: String to be parsed
170 : : * @option: option name
171 : : *
172 : : * This function parses a string containing a comma-separated list of
173 : : * strings like a=b,c.
174 : : *
175 : : * Return true if there's such option in the string, or return false.
176 : : */
177 : 11385 : bool parse_option_str(const char *str, const char *option)
178 : : {
179 [ - + ]: 22770 : while (*str) {
180 [ # # ]: 0 : if (!strncmp(str, option, strlen(option))) {
181 : 0 : str += strlen(option);
182 [ # # ]: 0 : if (!*str || *str == ',')
183 : : return true;
184 : : }
185 : :
186 [ # # ]: 0 : while (*str && *str != ',')
187 : 0 : str++;
188 : :
189 [ # # ]: 0 : if (*str == ',')
190 : 0 : str++;
191 : : }
192 : :
193 : : return false;
194 : : }
195 : :
196 : : /*
197 : : * Parse a string to get a param value pair.
198 : : * You can use " around spaces, but can't escape ".
199 : : * Hyphens and underscores equivalent in parameter names.
200 : : */
201 : 39951 : char *next_arg(char *args, char **param, char **val)
202 : : {
203 : : unsigned int i, equals = 0;
204 : : int in_quote = 0, quoted = 0;
205 : : char *next;
206 : :
207 [ - + ]: 39951 : if (*args == '"') {
208 : 0 : args++;
209 : : in_quote = 1;
210 : : quoted = 1;
211 : : }
212 : :
213 [ + + ]: 833175 : for (i = 0; args[i]; i++) {
214 [ + + - + ]: 831105 : if (isspace(args[i]) && !in_quote)
215 : : break;
216 [ + + ]: 793224 : if (equals == 0) {
217 [ + + ]: 612513 : if (args[i] == '=')
218 : : equals = i;
219 : : }
220 [ - + ]: 793224 : if (args[i] == '"')
221 : 0 : in_quote = !in_quote;
222 : : }
223 : :
224 : 39951 : *param = args;
225 [ + + ]: 39951 : if (!equals)
226 : 8280 : *val = NULL;
227 : : else {
228 : 31671 : args[equals] = '\0';
229 : 31671 : *val = args + equals + 1;
230 : :
231 : : /* Don't include quotes in value. */
232 [ - + ]: 31671 : if (**val == '"') {
233 : 0 : (*val)++;
234 [ # # ]: 0 : if (args[i-1] == '"')
235 : 0 : args[i-1] = '\0';
236 : : }
237 : : }
238 [ - + # # ]: 39951 : if (quoted && args[i-1] == '"')
239 : 0 : args[i-1] = '\0';
240 : :
241 [ + + ]: 39951 : if (args[i]) {
242 : 37881 : args[i] = '\0';
243 : 37881 : next = args + i + 1;
244 : : } else
245 : 2070 : next = args + i;
246 : :
247 : : /* Chew up trailing spaces. */
248 : 39951 : return skip_spaces(next);
249 : : }
|