xref: /openbmc/linux/arch/x86/lib/cmdline.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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