diff options
Diffstat (limited to 'arch/x86/lib/cmdline.c')
| -rw-r--r-- | arch/x86/lib/cmdline.c | 105 | 
1 files changed, 105 insertions, 0 deletions
| diff --git a/arch/x86/lib/cmdline.c b/arch/x86/lib/cmdline.c index 5cc78bf57232..3261abb21ef4 100644 --- a/arch/x86/lib/cmdline.c +++ b/arch/x86/lib/cmdline.c @@ -104,7 +104,112 @@ __cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,  	return 0;	/* Buffer overrun */  } +/* + * Find a non-boolean option (i.e. option=argument). In accordance with + * standard Linux practice, if this option is repeated, this returns the + * last instance on the command line. + * + * @cmdline: the cmdline string + * @max_cmdline_size: the maximum size of cmdline + * @option: option string to look for + * @buffer: memory buffer to return the option argument + * @bufsize: size of the supplied memory buffer + * + * Returns the length of the argument (regardless of if it was + * truncated to fit in the buffer), or -1 on not found. + */ +static int +__cmdline_find_option(const char *cmdline, int max_cmdline_size, +		      const char *option, char *buffer, int bufsize) +{ +	char c; +	int pos = 0, len = -1; +	const char *opptr = NULL; +	char *bufptr = buffer; +	enum { +		st_wordstart = 0,	/* Start of word/after whitespace */ +		st_wordcmp,	/* Comparing this word */ +		st_wordskip,	/* Miscompare, skip */ +		st_bufcpy,	/* Copying this to buffer */ +	} state = st_wordstart; + +	if (!cmdline) +		return -1;      /* No command line */ + +	/* +	 * This 'pos' check ensures we do not overrun +	 * a non-NULL-terminated 'cmdline' +	 */ +	while (pos++ < max_cmdline_size) { +		c = *(char *)cmdline++; +		if (!c) +			break; + +		switch (state) { +		case st_wordstart: +			if (myisspace(c)) +				break; + +			state = st_wordcmp; +			opptr = option; +			/* fall through */ + +		case st_wordcmp: +			if ((c == '=') && !*opptr) { +				/* +				 * We matched all the way to the end of the +				 * option we were looking for, prepare to +				 * copy the argument. +				 */ +				len = 0; +				bufptr = buffer; +				state = st_bufcpy; +				break; +			} else if (c == *opptr++) { +				/* +				 * We are currently matching, so continue +				 * to the next character on the cmdline. +				 */ +				break; +			} +			state = st_wordskip; +			/* fall through */ + +		case st_wordskip: +			if (myisspace(c)) +				state = st_wordstart; +			break; + +		case st_bufcpy: +			if (myisspace(c)) { +				state = st_wordstart; +			} else { +				/* +				 * Increment len, but don't overrun the +				 * supplied buffer and leave room for the +				 * NULL terminator. +				 */ +				if (++len < bufsize) +					*bufptr++ = c; +			} +			break; +		} +	} + +	if (bufsize) +		*bufptr = '\0'; + +	return len; +} +  int cmdline_find_option_bool(const char *cmdline, const char *option)  {  	return __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option);  } + +int cmdline_find_option(const char *cmdline, const char *option, char *buffer, +			int bufsize) +{ +	return __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option, +				     buffer, bufsize); +} |