chiark / gitweb /
macro: introduce TAKE_PTR() macro
[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 = TAKE_PTR(ret);
212
213         return found;
214 }
215
216 int proc_cmdline_get_bool(const char *key, bool *ret) {
217         _cleanup_free_ char *v = NULL;
218         int r;
219
220         assert(ret);
221
222         r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
223         if (r < 0)
224                 return r;
225         if (r == 0) {
226                 *ret = false;
227                 return 0;
228         }
229
230         if (v) { /* parameter passed */
231                 r = parse_boolean(v);
232                 if (r < 0)
233                         return r;
234                 *ret = r;
235         } else /* no parameter passed */
236                 *ret = true;
237
238         return 1;
239 }
240
241 int shall_restore_state(void) {
242         bool ret;
243         int r;
244
245         r = proc_cmdline_get_bool("systemd.restore_state", &ret);
246         if (r < 0)
247                 return r;
248
249         return r > 0 ? ret : true;
250 }
251
252 static const char * const rlmap[] = {
253         "emergency", SPECIAL_EMERGENCY_TARGET,
254         "-b",        SPECIAL_EMERGENCY_TARGET,
255         "rescue",    SPECIAL_RESCUE_TARGET,
256         "single",    SPECIAL_RESCUE_TARGET,
257         "-s",        SPECIAL_RESCUE_TARGET,
258         "s",         SPECIAL_RESCUE_TARGET,
259         "S",         SPECIAL_RESCUE_TARGET,
260         "1",         SPECIAL_RESCUE_TARGET,
261         "2",         SPECIAL_MULTI_USER_TARGET,
262         "3",         SPECIAL_MULTI_USER_TARGET,
263         "4",         SPECIAL_MULTI_USER_TARGET,
264         "5",         SPECIAL_GRAPHICAL_TARGET,
265         NULL
266 };
267
268 static const char * const rlmap_initrd[] = {
269         "emergency", SPECIAL_EMERGENCY_TARGET,
270         "rescue",    SPECIAL_RESCUE_TARGET,
271         NULL
272 };
273
274 const char* runlevel_to_target(const char *word) {
275         const char * const *rlmap_ptr;
276         size_t i;
277
278         if (!word)
279                 return NULL;
280
281         if (in_initrd()) {
282                 word = startswith(word, "rd.");
283                 if (!word)
284                         return NULL;
285         }
286
287         rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap;
288
289         for (i = 0; rlmap_ptr[i]; i += 2)
290                 if (streq(word, rlmap_ptr[i]))
291                         return rlmap_ptr[i+1];
292
293         return NULL;
294 }
295 #endif // 0