chiark / gitweb /
Prep v236 : Add missing SPDX-License-Identifier (2/9) src/basic
[elogind.git] / src / basic / proc-cmdline.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <string.h>
24
25 #include "alloc-util.h"
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"
32 //#include "special.h"
33 #include "string-util.h"
34 #include "util.h"
35 #include "virt.h"
36
37 int proc_cmdline(char **ret) {
38         const char *e;
39         assert(ret);
40
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
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
60 int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) {
61
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;
75                 char *value, *key, *q;
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
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                 }
94
95                 value = strchr(key, '=');
96                 if (value)
97                         *(value++) = 0;
98
99                 r = parse_item(key, value, data);
100                 if (r < 0)
101                         return r;
102         }
103
104         return 0;
105 }
106
107 static bool relaxed_equal_char(char a, char b) {
108
109         return a == b ||
110                 (a == '_' && b == '-') ||
111                 (a == '-' && b == '_');
112 }
113
114 #if 0 /// UNNEEDED by elogind
115 char *proc_cmdline_key_startswith(const char *s, const char *prefix) {
116
117         assert(s);
118         assert(prefix);
119
120         /* Much like startswith(), but considers "-" and "_" the same */
121
122         for (; *prefix != 0; s++, prefix++)
123                 if (!relaxed_equal_char(*s, *prefix))
124                         return NULL;
125
126         return (char*) s;
127 }
128 #endif // 0
129
130 bool proc_cmdline_key_streq(const char *x, const char *y) {
131         assert(x);
132         assert(y);
133
134         /* Much like streq(), but considers "-" and "_" the same */
135
136         for (; *x != 0 || *y != 0; x++, y++)
137                 if (!relaxed_equal_char(*x, *y))
138                         return false;
139
140         return true;
141 }
142
143 #if 0 /// UNNEEDED by elogind
144 int proc_cmdline_get_key(const char *key, unsigned flags, char **value) {
145         _cleanup_free_ char *line = NULL, *ret = NULL;
146         bool found = false;
147         const char *p;
148         int r;
149
150         /* Looks for a specific key on the kernel command line. Supports two modes:
151          *
152          * a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "="
153          *    is searched, and the value following this is returned in "value".
154          *
155          * b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the key is found as a
156          *    separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then
157          *    this is also accepted, and "value" is returned as NULL.
158          *
159          * c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
160          *
161          * In all three cases, > 0 is returned if the key is found, 0 if not. */
162
163         if (isempty(key))
164                 return -EINVAL;
165
166         if ((flags & PROC_CMDLINE_VALUE_OPTIONAL) && !value)
167                 return -EINVAL;
168
169         r = proc_cmdline(&line);
170         if (r < 0)
171                 return r;
172
173         p = line;
174         for (;;) {
175                 _cleanup_free_ char *word = NULL;
176                 const char *e;
177
178                 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
179                 if (r < 0)
180                         return r;
181                 if (r == 0)
182                         break;
183
184                 /* Automatically filter out arguments that are intended only for the initrd, if we are not in the
185                  * initrd. */
186                 if (!in_initrd() && startswith(word, "rd."))
187                         continue;
188
189                 if (value) {
190                         e = proc_cmdline_key_startswith(word, key);
191                         if (!e)
192                                 continue;
193
194                         if (*e == '=') {
195                                 r = free_and_strdup(&ret, e+1);
196                                 if (r < 0)
197                                         return r;
198
199                                 found = true;
200
201                         } else if (*e == 0 && (flags & PROC_CMDLINE_VALUE_OPTIONAL))
202                                 found = true;
203
204                 } else {
205                         if (streq(word, key))
206                                 found = true;
207                 }
208         }
209
210         if (value) {
211                 *value = ret;
212                 ret = NULL;
213         }
214
215         return found;
216 }
217
218 int proc_cmdline_get_bool(const char *key, bool *ret) {
219         _cleanup_free_ char *v = NULL;
220         int r;
221
222         assert(ret);
223
224         r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
225         if (r < 0)
226                 return r;
227         if (r == 0) {
228                 *ret = false;
229                 return 0;
230         }
231
232         if (v) { /* parameter passed */
233                 r = parse_boolean(v);
234                 if (r < 0)
235                         return r;
236                 *ret = r;
237         } else /* no parameter passed */
238                 *ret = true;
239
240         return 1;
241 }
242
243 int shall_restore_state(void) {
244         bool ret;
245         int r;
246
247         r = proc_cmdline_get_bool("systemd.restore_state", &ret);
248         if (r < 0)
249                 return r;
250
251         return r > 0 ? ret : true;
252 }
253
254 static const char * const rlmap[] = {
255         "emergency", SPECIAL_EMERGENCY_TARGET,
256         "-b",        SPECIAL_EMERGENCY_TARGET,
257         "rescue",    SPECIAL_RESCUE_TARGET,
258         "single",    SPECIAL_RESCUE_TARGET,
259         "-s",        SPECIAL_RESCUE_TARGET,
260         "s",         SPECIAL_RESCUE_TARGET,
261         "S",         SPECIAL_RESCUE_TARGET,
262         "1",         SPECIAL_RESCUE_TARGET,
263         "2",         SPECIAL_MULTI_USER_TARGET,
264         "3",         SPECIAL_MULTI_USER_TARGET,
265         "4",         SPECIAL_MULTI_USER_TARGET,
266         "5",         SPECIAL_GRAPHICAL_TARGET,
267         NULL
268 };
269
270 static const char * const rlmap_initrd[] = {
271         "emergency", SPECIAL_EMERGENCY_TARGET,
272         "rescue",    SPECIAL_RESCUE_TARGET,
273         NULL
274 };
275
276 const char* runlevel_to_target(const char *word) {
277         const char * const *rlmap_ptr;
278         size_t i;
279
280         if (!word)
281                 return NULL;
282
283         if (in_initrd()) {
284                 word = startswith(word, "rd.");
285                 if (!word)
286                         return NULL;
287         }
288
289         rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap;
290
291         for (i = 0; rlmap_ptr[i]; i += 2)
292                 if (streq(word, rlmap_ptr[i]))
293                         return rlmap_ptr[i+1];
294
295         return NULL;
296 }
297 #endif // 0