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