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