197873a3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21b1ded57SBorislav Petkov /*
31b1ded57SBorislav Petkov *
41b1ded57SBorislav Petkov * Misc librarized functions for cmdline poking.
51b1ded57SBorislav Petkov */
61b1ded57SBorislav Petkov #include <linux/kernel.h>
71b1ded57SBorislav Petkov #include <linux/string.h>
81b1ded57SBorislav Petkov #include <linux/ctype.h>
91b1ded57SBorislav Petkov #include <asm/setup.h>
10*65c24d7bSAnuradha Weeraman #include <asm/cmdline.h>
111b1ded57SBorislav Petkov
myisspace(u8 c)121b1ded57SBorislav Petkov static inline int myisspace(u8 c)
131b1ded57SBorislav Petkov {
141b1ded57SBorislav Petkov return c <= ' '; /* Close enough approximation */
151b1ded57SBorislav Petkov }
161b1ded57SBorislav Petkov
17*65c24d7bSAnuradha Weeraman /*
181b1ded57SBorislav Petkov * Find a boolean option (like quiet,noapic,nosmp....)
191b1ded57SBorislav Petkov *
201b1ded57SBorislav Petkov * @cmdline: the cmdline string
21*65c24d7bSAnuradha Weeraman * @max_cmdline_size: the maximum size of cmdline
221b1ded57SBorislav Petkov * @option: option string to look for
231b1ded57SBorislav Petkov *
241b1ded57SBorislav Petkov * Returns the position of that @option (starts counting with 1)
2502afeaaeSDave Hansen * or 0 on not found. @option will only be found if it is found
2602afeaaeSDave Hansen * as an entire word in @cmdline. For instance, if @option="car"
2702afeaaeSDave Hansen * then a cmdline which contains "cart" will not match.
281b1ded57SBorislav Petkov */
298c051775SDave Hansen static int
__cmdline_find_option_bool(const char * cmdline,int max_cmdline_size,const char * option)308c051775SDave Hansen __cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,
318c051775SDave Hansen const char *option)
321b1ded57SBorislav Petkov {
331b1ded57SBorislav Petkov char c;
3402afeaaeSDave Hansen int pos = 0, wstart = 0;
351b1ded57SBorislav Petkov const char *opptr = NULL;
361b1ded57SBorislav Petkov enum {
371b1ded57SBorislav Petkov st_wordstart = 0, /* Start of word/after whitespace */
381b1ded57SBorislav Petkov st_wordcmp, /* Comparing this word */
391b1ded57SBorislav Petkov st_wordskip, /* Miscompare, skip */
401b1ded57SBorislav Petkov } state = st_wordstart;
411b1ded57SBorislav Petkov
421b1ded57SBorislav Petkov if (!cmdline)
431b1ded57SBorislav Petkov return -1; /* No command line */
441b1ded57SBorislav Petkov
4502afeaaeSDave Hansen /*
4602afeaaeSDave Hansen * This 'pos' check ensures we do not overrun
4702afeaaeSDave Hansen * a non-NULL-terminated 'cmdline'
4802afeaaeSDave Hansen */
498c051775SDave Hansen while (pos < max_cmdline_size) {
501b1ded57SBorislav Petkov c = *(char *)cmdline++;
511b1ded57SBorislav Petkov pos++;
521b1ded57SBorislav Petkov
531b1ded57SBorislav Petkov switch (state) {
541b1ded57SBorislav Petkov case st_wordstart:
551b1ded57SBorislav Petkov if (!c)
561b1ded57SBorislav Petkov return 0;
571b1ded57SBorislav Petkov else if (myisspace(c))
581b1ded57SBorislav Petkov break;
591b1ded57SBorislav Petkov
601b1ded57SBorislav Petkov state = st_wordcmp;
611b1ded57SBorislav Petkov opptr = option;
621b1ded57SBorislav Petkov wstart = pos;
63df561f66SGustavo A. R. Silva fallthrough;
641b1ded57SBorislav Petkov
651b1ded57SBorislav Petkov case st_wordcmp:
6602afeaaeSDave Hansen if (!*opptr) {
6702afeaaeSDave Hansen /*
6802afeaaeSDave Hansen * We matched all the way to the end of the
6902afeaaeSDave Hansen * option we were looking for. If the
7002afeaaeSDave Hansen * command-line has a space _or_ ends, then
7102afeaaeSDave Hansen * we matched!
7202afeaaeSDave Hansen */
731b1ded57SBorislav Petkov if (!c || myisspace(c))
741b1ded57SBorislav Petkov return wstart;
75abcdc1c6SDave Hansen /*
76abcdc1c6SDave Hansen * We hit the end of the option, but _not_
77abcdc1c6SDave Hansen * the end of a word on the cmdline. Not
78abcdc1c6SDave Hansen * a match.
79abcdc1c6SDave Hansen */
8002afeaaeSDave Hansen } else if (!c) {
8102afeaaeSDave Hansen /*
8202afeaaeSDave Hansen * Hit the NULL terminator on the end of
8302afeaaeSDave Hansen * cmdline.
8402afeaaeSDave Hansen */
851b1ded57SBorislav Petkov return 0;
86abcdc1c6SDave Hansen } else if (c == *opptr++) {
87abcdc1c6SDave Hansen /*
88abcdc1c6SDave Hansen * We are currently matching, so continue
89abcdc1c6SDave Hansen * to the next character on the cmdline.
90abcdc1c6SDave Hansen */
911b1ded57SBorislav Petkov break;
92abcdc1c6SDave Hansen }
93abcdc1c6SDave Hansen state = st_wordskip;
94df561f66SGustavo A. R. Silva fallthrough;
951b1ded57SBorislav Petkov
961b1ded57SBorislav Petkov case st_wordskip:
971b1ded57SBorislav Petkov if (!c)
981b1ded57SBorislav Petkov return 0;
991b1ded57SBorislav Petkov else if (myisspace(c))
1001b1ded57SBorislav Petkov state = st_wordstart;
1011b1ded57SBorislav Petkov break;
1021b1ded57SBorislav Petkov }
1031b1ded57SBorislav Petkov }
1041b1ded57SBorislav Petkov
1051b1ded57SBorislav Petkov return 0; /* Buffer overrun */
1061b1ded57SBorislav Petkov }
1078c051775SDave Hansen
108e505371dSTom Lendacky /*
109e505371dSTom Lendacky * Find a non-boolean option (i.e. option=argument). In accordance with
110e505371dSTom Lendacky * standard Linux practice, if this option is repeated, this returns the
111e505371dSTom Lendacky * last instance on the command line.
112e505371dSTom Lendacky *
113e505371dSTom Lendacky * @cmdline: the cmdline string
114e505371dSTom Lendacky * @max_cmdline_size: the maximum size of cmdline
115e505371dSTom Lendacky * @option: option string to look for
116e505371dSTom Lendacky * @buffer: memory buffer to return the option argument
117e505371dSTom Lendacky * @bufsize: size of the supplied memory buffer
118e505371dSTom Lendacky *
119e505371dSTom Lendacky * Returns the length of the argument (regardless of if it was
120e505371dSTom Lendacky * truncated to fit in the buffer), or -1 on not found.
121e505371dSTom Lendacky */
122e505371dSTom Lendacky static int
__cmdline_find_option(const char * cmdline,int max_cmdline_size,const char * option,char * buffer,int bufsize)123e505371dSTom Lendacky __cmdline_find_option(const char *cmdline, int max_cmdline_size,
124e505371dSTom Lendacky const char *option, char *buffer, int bufsize)
125e505371dSTom Lendacky {
126e505371dSTom Lendacky char c;
127e505371dSTom Lendacky int pos = 0, len = -1;
128e505371dSTom Lendacky const char *opptr = NULL;
129e505371dSTom Lendacky char *bufptr = buffer;
130e505371dSTom Lendacky enum {
131e505371dSTom Lendacky st_wordstart = 0, /* Start of word/after whitespace */
132e505371dSTom Lendacky st_wordcmp, /* Comparing this word */
133e505371dSTom Lendacky st_wordskip, /* Miscompare, skip */
134e505371dSTom Lendacky st_bufcpy, /* Copying this to buffer */
135e505371dSTom Lendacky } state = st_wordstart;
136e505371dSTom Lendacky
137e505371dSTom Lendacky if (!cmdline)
138e505371dSTom Lendacky return -1; /* No command line */
139e505371dSTom Lendacky
140e505371dSTom Lendacky /*
141e505371dSTom Lendacky * This 'pos' check ensures we do not overrun
142e505371dSTom Lendacky * a non-NULL-terminated 'cmdline'
143e505371dSTom Lendacky */
144e505371dSTom Lendacky while (pos++ < max_cmdline_size) {
145e505371dSTom Lendacky c = *(char *)cmdline++;
146e505371dSTom Lendacky if (!c)
147e505371dSTom Lendacky break;
148e505371dSTom Lendacky
149e505371dSTom Lendacky switch (state) {
150e505371dSTom Lendacky case st_wordstart:
151e505371dSTom Lendacky if (myisspace(c))
152e505371dSTom Lendacky break;
153e505371dSTom Lendacky
154e505371dSTom Lendacky state = st_wordcmp;
155e505371dSTom Lendacky opptr = option;
156df561f66SGustavo A. R. Silva fallthrough;
157e505371dSTom Lendacky
158e505371dSTom Lendacky case st_wordcmp:
159e505371dSTom Lendacky if ((c == '=') && !*opptr) {
160e505371dSTom Lendacky /*
161e505371dSTom Lendacky * We matched all the way to the end of the
162e505371dSTom Lendacky * option we were looking for, prepare to
163e505371dSTom Lendacky * copy the argument.
164e505371dSTom Lendacky */
165e505371dSTom Lendacky len = 0;
166e505371dSTom Lendacky bufptr = buffer;
167e505371dSTom Lendacky state = st_bufcpy;
168e505371dSTom Lendacky break;
169e505371dSTom Lendacky } else if (c == *opptr++) {
170e505371dSTom Lendacky /*
171e505371dSTom Lendacky * We are currently matching, so continue
172e505371dSTom Lendacky * to the next character on the cmdline.
173e505371dSTom Lendacky */
174e505371dSTom Lendacky break;
175e505371dSTom Lendacky }
176e505371dSTom Lendacky state = st_wordskip;
177df561f66SGustavo A. R. Silva fallthrough;
178e505371dSTom Lendacky
179e505371dSTom Lendacky case st_wordskip:
180e505371dSTom Lendacky if (myisspace(c))
181e505371dSTom Lendacky state = st_wordstart;
182e505371dSTom Lendacky break;
183e505371dSTom Lendacky
184e505371dSTom Lendacky case st_bufcpy:
185e505371dSTom Lendacky if (myisspace(c)) {
186e505371dSTom Lendacky state = st_wordstart;
187e505371dSTom Lendacky } else {
188e505371dSTom Lendacky /*
189e505371dSTom Lendacky * Increment len, but don't overrun the
190e505371dSTom Lendacky * supplied buffer and leave room for the
191e505371dSTom Lendacky * NULL terminator.
192e505371dSTom Lendacky */
193e505371dSTom Lendacky if (++len < bufsize)
194e505371dSTom Lendacky *bufptr++ = c;
195e505371dSTom Lendacky }
196e505371dSTom Lendacky break;
197e505371dSTom Lendacky }
198e505371dSTom Lendacky }
199e505371dSTom Lendacky
200e505371dSTom Lendacky if (bufsize)
201e505371dSTom Lendacky *bufptr = '\0';
202e505371dSTom Lendacky
203e505371dSTom Lendacky return len;
204e505371dSTom Lendacky }
205e505371dSTom Lendacky
cmdline_find_option_bool(const char * cmdline,const char * option)2068c051775SDave Hansen int cmdline_find_option_bool(const char *cmdline, const char *option)
2078c051775SDave Hansen {
2088c051775SDave Hansen return __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option);
2098c051775SDave Hansen }
210e505371dSTom Lendacky
cmdline_find_option(const char * cmdline,const char * option,char * buffer,int bufsize)211e505371dSTom Lendacky int cmdline_find_option(const char *cmdline, const char *option, char *buffer,
212e505371dSTom Lendacky int bufsize)
213e505371dSTom Lendacky {
214e505371dSTom Lendacky return __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option,
215e505371dSTom Lendacky buffer, bufsize);
216e505371dSTom Lendacky }
217