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