]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/proc-cmdline.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / proc-cmdline.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
4e731273
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
11c3a366
TA
21#include <stdbool.h>
22#include <stddef.h>
23#include <string.h>
24
b5efdb8a 25#include "alloc-util.h"
4e731273
LP
26#include "extract-word.h"
27#include "fileio.h"
28#include "macro.h"
29#include "parse-util.h"
30#include "proc-cmdline.h"
31#include "process-util.h"
c573dcfe 32#include "special.h"
4e731273
LP
33#include "string-util.h"
34#include "util.h"
35#include "virt.h"
36
37int proc_cmdline(char **ret) {
2467cc55 38 const char *e;
4e731273
LP
39 assert(ret);
40
2467cc55
LP
41 /* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */
42 e = secure_getenv("SYSTEMD_PROC_CMDLINE");
43 if (e) {
44 char *m;
45
46 m = strdup(e);
47 if (!m)
48 return -ENOMEM;
49
50 *ret = m;
51 return 0;
52 }
53
4e731273
LP
54 if (detect_container() > 0)
55 return get_process_cmdline(1, 0, false, ret);
56 else
57 return read_one_line_file("/proc/cmdline", ret);
58}
59
1d84ad94
LP
60int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) {
61
4e731273
LP
62 _cleanup_free_ char *line = NULL;
63 const char *p;
64 int r;
65
66 assert(parse_item);
67
68 r = proc_cmdline(&line);
69 if (r < 0)
70 return r;
71
72 p = line;
73 for (;;) {
74 _cleanup_free_ char *word = NULL;
1d84ad94 75 char *value, *key, *q;
4e731273
LP
76
77 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
78 if (r < 0)
79 return r;
80 if (r == 0)
81 break;
82
1d84ad94
LP
83 key = word;
84
85 /* Filter out arguments that are intended only for the initrd */
86 q = startswith(word, "rd.");
87 if (q) {
88 if (!in_initrd())
89 continue;
90
91 if (flags & PROC_CMDLINE_STRIP_RD_PREFIX)
92 key = q;
93 }
4e731273 94
1d84ad94 95 value = strchr(key, '=');
4e731273
LP
96 if (value)
97 *(value++) = 0;
98
1d84ad94 99 r = parse_item(key, value, data);
4e731273
LP
100 if (r < 0)
101 return r;
102 }
103
104 return 0;
105}
106
1d84ad94
LP
107static bool relaxed_equal_char(char a, char b) {
108
109 return a == b ||
110 (a == '_' && b == '-') ||
111 (a == '-' && b == '_');
112}
113
114char *proc_cmdline_key_startswith(const char *s, const char *prefix) {
115
116 assert(s);
117 assert(prefix);
118
119 /* Much like startswith(), but considers "-" and "_" the same */
120
121 for (; *prefix != 0; s++, prefix++)
122 if (!relaxed_equal_char(*s, *prefix))
123 return NULL;
124
125 return (char*) s;
126}
127
128bool proc_cmdline_key_streq(const char *x, const char *y) {
129 assert(x);
130 assert(y);
131
132 /* Much like streq(), but considers "-" and "_" the same */
133
134 for (; *x != 0 || *y != 0; x++, y++)
135 if (!relaxed_equal_char(*x, *y))
136 return false;
137
138 return true;
139}
140
141int proc_cmdline_get_key(const char *key, unsigned flags, char **value) {
4e731273
LP
142 _cleanup_free_ char *line = NULL, *ret = NULL;
143 bool found = false;
144 const char *p;
145 int r;
146
1d84ad94
LP
147 /* Looks for a specific key on the kernel command line. Supports two modes:
148 *
149 * a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "="
150 * is searched, and the value following this is returned in "value".
151 *
1a012455 152 * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a
1d84ad94
LP
153 * separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then
154 * this is also accepted, and "value" is returned as NULL.
155 *
156 * c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
157 *
13e785f7 158 * In all three cases, > 0 is returned if the key is found, 0 if not. */
1d84ad94
LP
159
160 if (isempty(key))
161 return -EINVAL;
162
163 if ((flags & PROC_CMDLINE_VALUE_OPTIONAL) && !value)
164 return -EINVAL;
4e731273
LP
165
166 r = proc_cmdline(&line);
167 if (r < 0)
168 return r;
169
170 p = line;
171 for (;;) {
172 _cleanup_free_ char *word = NULL;
173 const char *e;
174
175 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
176 if (r < 0)
177 return r;
178 if (r == 0)
179 break;
180
1d84ad94
LP
181 /* Automatically filter out arguments that are intended only for the initrd, if we are not in the
182 * initrd. */
4e731273
LP
183 if (!in_initrd() && startswith(word, "rd."))
184 continue;
185
186 if (value) {
1d84ad94 187 e = proc_cmdline_key_startswith(word, key);
4e731273
LP
188 if (!e)
189 continue;
190
1d84ad94
LP
191 if (*e == '=') {
192 r = free_and_strdup(&ret, e+1);
193 if (r < 0)
194 return r;
195
196 found = true;
197
198 } else if (*e == 0 && (flags & PROC_CMDLINE_VALUE_OPTIONAL))
199 found = true;
4e731273 200
4e731273
LP
201 } else {
202 if (streq(word, key))
203 found = true;
204 }
205 }
206
207 if (value) {
208 *value = ret;
209 ret = NULL;
210 }
211
212 return found;
1d84ad94
LP
213}
214
215int proc_cmdline_get_bool(const char *key, bool *ret) {
216 _cleanup_free_ char *v = NULL;
217 int r;
218
219 assert(ret);
220
221 r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
222 if (r < 0)
223 return r;
224 if (r == 0) {
225 *ret = false;
226 return 0;
227 }
228
229 if (v) { /* parameter passed */
230 r = parse_boolean(v);
231 if (r < 0)
232 return r;
233 *ret = r;
234 } else /* no parameter passed */
235 *ret = true;
4e731273 236
1d84ad94 237 return 1;
4e731273
LP
238}
239
240int shall_restore_state(void) {
1d84ad94 241 bool ret;
4e731273
LP
242 int r;
243
1d84ad94 244 r = proc_cmdline_get_bool("systemd.restore_state", &ret);
4e731273
LP
245 if (r < 0)
246 return r;
4e731273 247
1d84ad94 248 return r > 0 ? ret : true;
4e731273 249}
c573dcfe
EV
250
251static const char * const rlmap[] = {
252 "emergency", SPECIAL_EMERGENCY_TARGET,
253 "-b", SPECIAL_EMERGENCY_TARGET,
254 "rescue", SPECIAL_RESCUE_TARGET,
255 "single", SPECIAL_RESCUE_TARGET,
256 "-s", SPECIAL_RESCUE_TARGET,
257 "s", SPECIAL_RESCUE_TARGET,
258 "S", SPECIAL_RESCUE_TARGET,
259 "1", SPECIAL_RESCUE_TARGET,
260 "2", SPECIAL_MULTI_USER_TARGET,
261 "3", SPECIAL_MULTI_USER_TARGET,
262 "4", SPECIAL_MULTI_USER_TARGET,
263 "5", SPECIAL_GRAPHICAL_TARGET,
dcd61450
IS
264 NULL
265};
266
267static const char * const rlmap_initrd[] = {
268 "emergency", SPECIAL_EMERGENCY_TARGET,
269 "rescue", SPECIAL_RESCUE_TARGET,
270 NULL
c573dcfe
EV
271};
272
273const char* runlevel_to_target(const char *word) {
274 size_t i;
dcd61450
IS
275 const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd
276 : rlmap;
c573dcfe
EV
277
278 if (!word)
279 return NULL;
280
dcd61450
IS
281 if (in_initrd() && (word = startswith(word, "rd.")) == NULL)
282 return NULL;
283
284 for (i = 0; rlmap_ptr[i] != NULL; i += 2)
285 if (streq(word, rlmap_ptr[i]))
286 return rlmap_ptr[i+1];
c573dcfe
EV
287
288 return NULL;
289}