]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/proc-cmdline.c
util: introduce memcmp_safe()
[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
1d84ad94
LP
42int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) {
43
4e731273
LP
44 _cleanup_free_ char *line = NULL;
45 const char *p;
46 int r;
47
48 assert(parse_item);
49
50 r = proc_cmdline(&line);
51 if (r < 0)
52 return r;
53
54 p = line;
55 for (;;) {
56 _cleanup_free_ char *word = NULL;
1d84ad94 57 char *value, *key, *q;
4e731273
LP
58
59 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
60 if (r < 0)
61 return r;
62 if (r == 0)
63 break;
64
1d84ad94
LP
65 key = word;
66
67 /* Filter out arguments that are intended only for the initrd */
68 q = startswith(word, "rd.");
69 if (q) {
70 if (!in_initrd())
71 continue;
72
73 if (flags & PROC_CMDLINE_STRIP_RD_PREFIX)
74 key = q;
75 }
4e731273 76
1d84ad94 77 value = strchr(key, '=');
4e731273
LP
78 if (value)
79 *(value++) = 0;
80
1d84ad94 81 r = parse_item(key, value, data);
4e731273
LP
82 if (r < 0)
83 return r;
84 }
85
86 return 0;
87}
88
1d84ad94
LP
89static bool relaxed_equal_char(char a, char b) {
90
91 return a == b ||
92 (a == '_' && b == '-') ||
93 (a == '-' && b == '_');
94}
95
96char *proc_cmdline_key_startswith(const char *s, const char *prefix) {
97
98 assert(s);
99 assert(prefix);
100
101 /* Much like startswith(), but considers "-" and "_" the same */
102
103 for (; *prefix != 0; s++, prefix++)
104 if (!relaxed_equal_char(*s, *prefix))
105 return NULL;
106
107 return (char*) s;
108}
109
110bool proc_cmdline_key_streq(const char *x, const char *y) {
111 assert(x);
112 assert(y);
113
114 /* Much like streq(), but considers "-" and "_" the same */
115
116 for (; *x != 0 || *y != 0; x++, y++)
117 if (!relaxed_equal_char(*x, *y))
118 return false;
119
120 return true;
121}
122
123int proc_cmdline_get_key(const char *key, unsigned flags, char **value) {
4e731273
LP
124 _cleanup_free_ char *line = NULL, *ret = NULL;
125 bool found = false;
126 const char *p;
127 int r;
128
1d84ad94
LP
129 /* Looks for a specific key on the kernel command line. Supports two modes:
130 *
131 * a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "="
132 * is searched, and the value following this is returned in "value".
133 *
1a012455 134 * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a
1d84ad94
LP
135 * separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then
136 * this is also accepted, and "value" is returned as NULL.
137 *
138 * c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
139 *
13e785f7 140 * In all three cases, > 0 is returned if the key is found, 0 if not. */
1d84ad94
LP
141
142 if (isempty(key))
143 return -EINVAL;
144
145 if ((flags & PROC_CMDLINE_VALUE_OPTIONAL) && !value)
146 return -EINVAL;
4e731273
LP
147
148 r = proc_cmdline(&line);
149 if (r < 0)
150 return r;
151
152 p = line;
153 for (;;) {
154 _cleanup_free_ char *word = NULL;
155 const char *e;
156
157 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
158 if (r < 0)
159 return r;
160 if (r == 0)
161 break;
162
1d84ad94
LP
163 /* Automatically filter out arguments that are intended only for the initrd, if we are not in the
164 * initrd. */
4e731273
LP
165 if (!in_initrd() && startswith(word, "rd."))
166 continue;
167
168 if (value) {
1d84ad94 169 e = proc_cmdline_key_startswith(word, key);
4e731273
LP
170 if (!e)
171 continue;
172
1d84ad94
LP
173 if (*e == '=') {
174 r = free_and_strdup(&ret, e+1);
175 if (r < 0)
176 return r;
177
178 found = true;
179
180 } else if (*e == 0 && (flags & PROC_CMDLINE_VALUE_OPTIONAL))
181 found = true;
4e731273 182
4e731273
LP
183 } else {
184 if (streq(word, key))
185 found = true;
186 }
187 }
188
ae2a15bc
LP
189 if (value)
190 *value = TAKE_PTR(ret);
4e731273
LP
191
192 return found;
1d84ad94
LP
193}
194
195int proc_cmdline_get_bool(const char *key, bool *ret) {
196 _cleanup_free_ char *v = NULL;
197 int r;
198
199 assert(ret);
200
201 r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
202 if (r < 0)
203 return r;
204 if (r == 0) {
205 *ret = false;
206 return 0;
207 }
208
209 if (v) { /* parameter passed */
210 r = parse_boolean(v);
211 if (r < 0)
212 return r;
213 *ret = r;
214 } else /* no parameter passed */
215 *ret = true;
4e731273 216
1d84ad94 217 return 1;
4e731273
LP
218}
219
220int shall_restore_state(void) {
1d84ad94 221 bool ret;
4e731273
LP
222 int r;
223
1d84ad94 224 r = proc_cmdline_get_bool("systemd.restore_state", &ret);
4e731273
LP
225 if (r < 0)
226 return r;
4e731273 227
1d84ad94 228 return r > 0 ? ret : true;
4e731273 229}
c573dcfe
EV
230
231static const char * const rlmap[] = {
232 "emergency", SPECIAL_EMERGENCY_TARGET,
233 "-b", SPECIAL_EMERGENCY_TARGET,
234 "rescue", SPECIAL_RESCUE_TARGET,
235 "single", SPECIAL_RESCUE_TARGET,
236 "-s", SPECIAL_RESCUE_TARGET,
237 "s", SPECIAL_RESCUE_TARGET,
238 "S", SPECIAL_RESCUE_TARGET,
239 "1", SPECIAL_RESCUE_TARGET,
240 "2", SPECIAL_MULTI_USER_TARGET,
241 "3", SPECIAL_MULTI_USER_TARGET,
242 "4", SPECIAL_MULTI_USER_TARGET,
243 "5", SPECIAL_GRAPHICAL_TARGET,
dcd61450
IS
244 NULL
245};
246
247static const char * const rlmap_initrd[] = {
248 "emergency", SPECIAL_EMERGENCY_TARGET,
249 "rescue", SPECIAL_RESCUE_TARGET,
250 NULL
c573dcfe
EV
251};
252
253const char* runlevel_to_target(const char *word) {
11f5d825 254 const char * const *rlmap_ptr;
c573dcfe
EV
255 size_t i;
256
257 if (!word)
258 return NULL;
259
11f5d825
LP
260 if (in_initrd()) {
261 word = startswith(word, "rd.");
262 if (!word)
263 return NULL;
264 }
265
266 rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap;
dcd61450 267
11f5d825 268 for (i = 0; rlmap_ptr[i]; i += 2)
dcd61450
IS
269 if (streq(word, rlmap_ptr[i]))
270 return rlmap_ptr[i+1];
c573dcfe
EV
271
272 return NULL;
273}