Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Misc librarized functions for cmdline poking.
0005  */
0006 #include <linux/kernel.h>
0007 #include <linux/string.h>
0008 #include <linux/ctype.h>
0009 #include <asm/setup.h>
0010 
0011 static inline int myisspace(u8 c)
0012 {
0013     return c <= ' ';    /* Close enough approximation */
0014 }
0015 
0016 /**
0017  * Find a boolean option (like quiet,noapic,nosmp....)
0018  *
0019  * @cmdline: the cmdline string
0020  * @option: option string to look for
0021  *
0022  * Returns the position of that @option (starts counting with 1)
0023  * or 0 on not found.  @option will only be found if it is found
0024  * as an entire word in @cmdline.  For instance, if @option="car"
0025  * then a cmdline which contains "cart" will not match.
0026  */
0027 static int
0028 __cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,
0029                const char *option)
0030 {
0031     char c;
0032     int pos = 0, wstart = 0;
0033     const char *opptr = NULL;
0034     enum {
0035         st_wordstart = 0,   /* Start of word/after whitespace */
0036         st_wordcmp, /* Comparing this word */
0037         st_wordskip,    /* Miscompare, skip */
0038     } state = st_wordstart;
0039 
0040     if (!cmdline)
0041         return -1;      /* No command line */
0042 
0043     /*
0044      * This 'pos' check ensures we do not overrun
0045      * a non-NULL-terminated 'cmdline'
0046      */
0047     while (pos < max_cmdline_size) {
0048         c = *(char *)cmdline++;
0049         pos++;
0050 
0051         switch (state) {
0052         case st_wordstart:
0053             if (!c)
0054                 return 0;
0055             else if (myisspace(c))
0056                 break;
0057 
0058             state = st_wordcmp;
0059             opptr = option;
0060             wstart = pos;
0061             fallthrough;
0062 
0063         case st_wordcmp:
0064             if (!*opptr) {
0065                 /*
0066                  * We matched all the way to the end of the
0067                  * option we were looking for.  If the
0068                  * command-line has a space _or_ ends, then
0069                  * we matched!
0070                  */
0071                 if (!c || myisspace(c))
0072                     return wstart;
0073                 /*
0074                  * We hit the end of the option, but _not_
0075                  * the end of a word on the cmdline.  Not
0076                  * a match.
0077                  */
0078             } else if (!c) {
0079                 /*
0080                  * Hit the NULL terminator on the end of
0081                  * cmdline.
0082                  */
0083                 return 0;
0084             } else if (c == *opptr++) {
0085                 /*
0086                  * We are currently matching, so continue
0087                  * to the next character on the cmdline.
0088                  */
0089                 break;
0090             }
0091             state = st_wordskip;
0092             fallthrough;
0093 
0094         case st_wordskip:
0095             if (!c)
0096                 return 0;
0097             else if (myisspace(c))
0098                 state = st_wordstart;
0099             break;
0100         }
0101     }
0102 
0103     return 0;   /* Buffer overrun */
0104 }
0105 
0106 /*
0107  * Find a non-boolean option (i.e. option=argument). In accordance with
0108  * standard Linux practice, if this option is repeated, this returns the
0109  * last instance on the command line.
0110  *
0111  * @cmdline: the cmdline string
0112  * @max_cmdline_size: the maximum size of cmdline
0113  * @option: option string to look for
0114  * @buffer: memory buffer to return the option argument
0115  * @bufsize: size of the supplied memory buffer
0116  *
0117  * Returns the length of the argument (regardless of if it was
0118  * truncated to fit in the buffer), or -1 on not found.
0119  */
0120 static int
0121 __cmdline_find_option(const char *cmdline, int max_cmdline_size,
0122               const char *option, char *buffer, int bufsize)
0123 {
0124     char c;
0125     int pos = 0, len = -1;
0126     const char *opptr = NULL;
0127     char *bufptr = buffer;
0128     enum {
0129         st_wordstart = 0,   /* Start of word/after whitespace */
0130         st_wordcmp, /* Comparing this word */
0131         st_wordskip,    /* Miscompare, skip */
0132         st_bufcpy,  /* Copying this to buffer */
0133     } state = st_wordstart;
0134 
0135     if (!cmdline)
0136         return -1;      /* No command line */
0137 
0138     /*
0139      * This 'pos' check ensures we do not overrun
0140      * a non-NULL-terminated 'cmdline'
0141      */
0142     while (pos++ < max_cmdline_size) {
0143         c = *(char *)cmdline++;
0144         if (!c)
0145             break;
0146 
0147         switch (state) {
0148         case st_wordstart:
0149             if (myisspace(c))
0150                 break;
0151 
0152             state = st_wordcmp;
0153             opptr = option;
0154             fallthrough;
0155 
0156         case st_wordcmp:
0157             if ((c == '=') && !*opptr) {
0158                 /*
0159                  * We matched all the way to the end of the
0160                  * option we were looking for, prepare to
0161                  * copy the argument.
0162                  */
0163                 len = 0;
0164                 bufptr = buffer;
0165                 state = st_bufcpy;
0166                 break;
0167             } else if (c == *opptr++) {
0168                 /*
0169                  * We are currently matching, so continue
0170                  * to the next character on the cmdline.
0171                  */
0172                 break;
0173             }
0174             state = st_wordskip;
0175             fallthrough;
0176 
0177         case st_wordskip:
0178             if (myisspace(c))
0179                 state = st_wordstart;
0180             break;
0181 
0182         case st_bufcpy:
0183             if (myisspace(c)) {
0184                 state = st_wordstart;
0185             } else {
0186                 /*
0187                  * Increment len, but don't overrun the
0188                  * supplied buffer and leave room for the
0189                  * NULL terminator.
0190                  */
0191                 if (++len < bufsize)
0192                     *bufptr++ = c;
0193             }
0194             break;
0195         }
0196     }
0197 
0198     if (bufsize)
0199         *bufptr = '\0';
0200 
0201     return len;
0202 }
0203 
0204 int cmdline_find_option_bool(const char *cmdline, const char *option)
0205 {
0206     return __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option);
0207 }
0208 
0209 int cmdline_find_option(const char *cmdline, const char *option, char *buffer,
0210             int bufsize)
0211 {
0212     return __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option,
0213                      buffer, bufsize);
0214 }