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