Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/lib/cmdline.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
*
4
* Misc librarized functions for cmdline poking.
5
*/
6
#include <linux/kernel.h>
7
#include <linux/string.h>
8
#include <linux/ctype.h>
9
10
#include <asm/setup.h>
11
#include <asm/cmdline.h>
12
#include <asm/bug.h>
13
14
static inline int myisspace(u8 c)
15
{
16
return c <= ' '; /* Close enough approximation */
17
}
18
19
/*
20
* Find a boolean option (like quiet,noapic,nosmp....)
21
*
22
* @cmdline: the cmdline string
23
* @max_cmdline_size: the maximum size of cmdline
24
* @option: option string to look for
25
*
26
* Returns the position of that @option (starts counting with 1)
27
* or 0 on not found. @option will only be found if it is found
28
* as an entire word in @cmdline. For instance, if @option="car"
29
* then a cmdline which contains "cart" will not match.
30
*/
31
static int
32
__cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,
33
const char *option)
34
{
35
char c;
36
int pos = 0, wstart = 0;
37
const char *opptr = NULL;
38
enum {
39
st_wordstart = 0, /* Start of word/after whitespace */
40
st_wordcmp, /* Comparing this word */
41
st_wordskip, /* Miscompare, skip */
42
} state = st_wordstart;
43
44
if (!cmdline)
45
return -1; /* No command line */
46
47
/*
48
* This 'pos' check ensures we do not overrun
49
* a non-NULL-terminated 'cmdline'
50
*/
51
while (pos < max_cmdline_size) {
52
c = *(char *)cmdline++;
53
pos++;
54
55
switch (state) {
56
case st_wordstart:
57
if (!c)
58
return 0;
59
else if (myisspace(c))
60
break;
61
62
state = st_wordcmp;
63
opptr = option;
64
wstart = pos;
65
fallthrough;
66
67
case st_wordcmp:
68
if (!*opptr) {
69
/*
70
* We matched all the way to the end of the
71
* option we were looking for. If the
72
* command-line has a space _or_ ends, then
73
* we matched!
74
*/
75
if (!c || myisspace(c))
76
return wstart;
77
/*
78
* We hit the end of the option, but _not_
79
* the end of a word on the cmdline. Not
80
* a match.
81
*/
82
} else if (!c) {
83
/*
84
* Hit the NULL terminator on the end of
85
* cmdline.
86
*/
87
return 0;
88
} else if (c == *opptr++) {
89
/*
90
* We are currently matching, so continue
91
* to the next character on the cmdline.
92
*/
93
break;
94
}
95
state = st_wordskip;
96
fallthrough;
97
98
case st_wordskip:
99
if (!c)
100
return 0;
101
else if (myisspace(c))
102
state = st_wordstart;
103
break;
104
}
105
}
106
107
return 0; /* Buffer overrun */
108
}
109
110
/*
111
* Find a non-boolean option (i.e. option=argument). In accordance with
112
* standard Linux practice, if this option is repeated, this returns the
113
* last instance on the command line.
114
*
115
* @cmdline: the cmdline string
116
* @max_cmdline_size: the maximum size of cmdline
117
* @option: option string to look for
118
* @buffer: memory buffer to return the option argument
119
* @bufsize: size of the supplied memory buffer
120
*
121
* Returns the length of the argument (regardless of if it was
122
* truncated to fit in the buffer), or -1 on not found.
123
*/
124
static int
125
__cmdline_find_option(const char *cmdline, int max_cmdline_size,
126
const char *option, char *buffer, int bufsize)
127
{
128
char c;
129
int pos = 0, len = -1;
130
const char *opptr = NULL;
131
char *bufptr = buffer;
132
enum {
133
st_wordstart = 0, /* Start of word/after whitespace */
134
st_wordcmp, /* Comparing this word */
135
st_wordskip, /* Miscompare, skip */
136
st_bufcpy, /* Copying this to buffer */
137
} state = st_wordstart;
138
139
if (!cmdline)
140
return -1; /* No command line */
141
142
/*
143
* This 'pos' check ensures we do not overrun
144
* a non-NULL-terminated 'cmdline'
145
*/
146
while (pos++ < max_cmdline_size) {
147
c = *(char *)cmdline++;
148
if (!c)
149
break;
150
151
switch (state) {
152
case st_wordstart:
153
if (myisspace(c))
154
break;
155
156
state = st_wordcmp;
157
opptr = option;
158
fallthrough;
159
160
case st_wordcmp:
161
if ((c == '=') && !*opptr) {
162
/*
163
* We matched all the way to the end of the
164
* option we were looking for, prepare to
165
* copy the argument.
166
*/
167
len = 0;
168
bufptr = buffer;
169
state = st_bufcpy;
170
break;
171
} else if (c == *opptr++) {
172
/*
173
* We are currently matching, so continue
174
* to the next character on the cmdline.
175
*/
176
break;
177
}
178
state = st_wordskip;
179
fallthrough;
180
181
case st_wordskip:
182
if (myisspace(c))
183
state = st_wordstart;
184
break;
185
186
case st_bufcpy:
187
if (myisspace(c)) {
188
state = st_wordstart;
189
} else {
190
/*
191
* Increment len, but don't overrun the
192
* supplied buffer and leave room for the
193
* NULL terminator.
194
*/
195
if (++len < bufsize)
196
*bufptr++ = c;
197
}
198
break;
199
}
200
}
201
202
if (bufsize)
203
*bufptr = '\0';
204
205
return len;
206
}
207
208
int cmdline_find_option_bool(const char *cmdline, const char *option)
209
{
210
int ret;
211
212
ret = __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option);
213
if (ret > 0)
214
return ret;
215
216
if (IS_ENABLED(CONFIG_CMDLINE_BOOL) && !builtin_cmdline_added)
217
return __cmdline_find_option_bool(builtin_cmdline, COMMAND_LINE_SIZE, option);
218
219
return ret;
220
}
221
222
int cmdline_find_option(const char *cmdline, const char *option, char *buffer,
223
int bufsize)
224
{
225
int ret;
226
227
ret = __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option, buffer, bufsize);
228
if (ret > 0)
229
return ret;
230
231
if (IS_ENABLED(CONFIG_CMDLINE_BOOL) && !builtin_cmdline_added)
232
return __cmdline_find_option(builtin_cmdline, COMMAND_LINE_SIZE, option, buffer, bufsize);
233
234
return ret;
235
}
236
237