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