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