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