]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/util.c
initrd: do a debug log if failed to detect rootfs type
[thirdparty/systemd.git] / src / basic / util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
a7334b09 2
60918275 3#include <errno.h>
f6c2284a 4#include <fcntl.h>
87d2c1ff 5#include <sys/mman.h>
eef46c37 6
b5efdb8a 7#include "alloc-util.h"
3f6fd1ba 8#include "build.h"
cf0fbc49 9#include "dirent-util.h"
686d13b9 10#include "env-file.h"
0307ea49 11#include "env-util.h"
3ffd4af2 12#include "fd-util.h"
f6c2284a 13#include "fileio.h"
f6c2284a 14#include "hostname-util.h"
a9f5d454 15#include "log.h"
f6c2284a 16#include "macro.h"
6bedfcbb 17#include "parse-util.h"
cf0fbc49 18#include "stat-util.h"
07630cea 19#include "string-util.h"
4f5dd394 20#include "util.h"
9ce17593 21#include "virt.h"
56cf987f 22
9a0e6896
LP
23int saved_argc = 0;
24char **saved_argv = NULL;
dcd61450 25static int saved_in_initrd = -1;
9086e840 26
65457142 27bool kexec_loaded(void) {
c47f86e6
ZJS
28 _cleanup_free_ char *s = NULL;
29
30 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
31 return false;
32
33 return s[0] == '1';
65457142 34}
fb9de93d 35
87d2c1ff
LP
36int prot_from_flags(int flags) {
37
38 switch (flags & O_ACCMODE) {
39
40 case O_RDONLY:
41 return PROT_READ;
42
43 case O_WRONLY:
44 return PROT_WRITE;
45
46 case O_RDWR:
47 return PROT_READ|PROT_WRITE;
48
49 default:
50 return -EINVAL;
51 }
7c99e0c1 52}
689b9a22 53
9be346c9 54bool in_initrd(void) {
0307ea49 55 int r;
1f22621b
KS
56 const char *e;
57 bool lenient = false;
8f33b5b8 58
dcd61450
IS
59 if (saved_in_initrd >= 0)
60 return saved_in_initrd;
825c6fe5 61
1f22621b 62 /* We have two checks here:
825c6fe5
LP
63 *
64 * 1. the flag file /etc/initrd-release must exist
65 * 2. the root file system must be a memory file system
66 *
67 * The second check is extra paranoia, since misdetecting an
629ff674 68 * initrd can have bad consequences due the initrd
825c6fe5 69 * emptying when transititioning to the main systemd.
1f22621b
KS
70 *
71 * If env var $SYSTEMD_IN_INITRD is not set or set to "auto",
72 * both checks are used. If it's set to "lenient", only check
73 * 1 is used. If set to a booleen value, then the boolean
74 * value is returned.
825c6fe5
LP
75 */
76
1f22621b
KS
77 e = secure_getenv("SYSTEMD_IN_INITRD");
78 if (e) {
79 if (streq(e, "lenient"))
80 lenient = true;
81 else if (!streq(e, "auto")) {
82 r = parse_boolean(e);
83 if (r >= 0) {
84 saved_in_initrd = r > 0;
85 return saved_in_initrd;
86 }
87 log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
88 }
89 }
0307ea49 90
3b9b9169
KS
91 if (!lenient) {
92 r = path_is_temporary_fs("/");
93 if (r < 0)
94 log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m");
95
96 saved_in_initrd = r > 0;
97 }
98
99 if (saved_in_initrd != 0)
100 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0;
9be346c9 101
dcd61450
IS
102 return saved_in_initrd;
103}
104
105void in_initrd_force(bool value) {
106 saved_in_initrd = value;
9be346c9 107}
069cfc85 108
240dbaa4
LP
109int on_ac_power(void) {
110 bool found_offline = false, found_online = false;
111 _cleanup_closedir_ DIR *d = NULL;
8fb3f009 112 struct dirent *de;
240dbaa4
LP
113
114 d = opendir("/sys/class/power_supply");
115 if (!d)
6d890034 116 return errno == ENOENT ? true : -errno;
240dbaa4 117
8fb3f009 118 FOREACH_DIRENT(de, d, return -errno) {
240dbaa4
LP
119 _cleanup_close_ int fd = -1, device = -1;
120 char contents[6];
121 ssize_t n;
240dbaa4 122
240dbaa4
LP
123 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
124 if (device < 0) {
3742095b 125 if (IN_SET(errno, ENOENT, ENOTDIR))
240dbaa4
LP
126 continue;
127
128 return -errno;
129 }
130
131 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
132 if (fd < 0) {
133 if (errno == ENOENT)
134 continue;
135
136 return -errno;
137 }
138
139 n = read(fd, contents, sizeof(contents));
140 if (n < 0)
141 return -errno;
142
143 if (n != 6 || memcmp(contents, "Mains\n", 6))
144 continue;
145
03e334a1 146 safe_close(fd);
240dbaa4
LP
147 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
148 if (fd < 0) {
149 if (errno == ENOENT)
150 continue;
151
152 return -errno;
153 }
154
155 n = read(fd, contents, sizeof(contents));
156 if (n < 0)
157 return -errno;
158
159 if (n != 2 || contents[1] != '\n')
160 return -EIO;
161
162 if (contents[0] == '1') {
163 found_online = true;
164 break;
165 } else if (contents[0] == '0')
166 found_offline = true;
167 else
168 return -EIO;
169 }
170
171 return found_online || !found_offline;
172}
fabe5c0e 173
bc9fd78c
LP
174int container_get_leader(const char *machine, pid_t *pid) {
175 _cleanup_free_ char *s = NULL, *class = NULL;
176 const char *p;
177 pid_t leader;
178 int r;
179
180 assert(machine);
181 assert(pid);
182
1e5057b9
LP
183 if (streq(machine, ".host")) {
184 *pid = 1;
185 return 0;
186 }
187
52ef5dd7 188 if (!hostname_is_valid(machine, 0))
b9a8d250
LP
189 return -EINVAL;
190
63c372cb 191 p = strjoina("/run/systemd/machines/", machine);
13df9c39
LP
192 r = parse_env_file(NULL, p,
193 "LEADER", &s,
194 "CLASS", &class);
bc9fd78c
LP
195 if (r == -ENOENT)
196 return -EHOSTDOWN;
197 if (r < 0)
198 return r;
199 if (!s)
200 return -EIO;
201
202 if (!streq_ptr(class, "container"))
203 return -EIO;
204
205 r = parse_pid(s, &leader);
206 if (r < 0)
207 return r;
208 if (leader <= 1)
209 return -EIO;
210
211 *pid = leader;
212 return 0;
213}
214
3f6fd1ba 215int version(void) {
91b79ba8
ZJS
216 printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n",
217 systemd_features);
3f6fd1ba
LP
218 return 0;
219}
68c58c67
LP
220
221/* This is a direct translation of str_verscmp from boot.c */
222static bool is_digit(int c) {
223 return c >= '0' && c <= '9';
224}
225
226static int c_order(int c) {
227 if (c == 0 || is_digit(c))
228 return 0;
229
230 if ((c >= 'a') && (c <= 'z'))
231 return c;
232
233 return c + 0x10000;
234}
235
236int str_verscmp(const char *s1, const char *s2) {
237 const char *os1, *os2;
238
239 assert(s1);
240 assert(s2);
241
242 os1 = s1;
243 os2 = s2;
244
245 while (*s1 || *s2) {
246 int first;
247
248 while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
249 int order;
250
251 order = c_order(*s1) - c_order(*s2);
252 if (order != 0)
253 return order;
254 s1++;
255 s2++;
256 }
257
258 while (*s1 == '0')
259 s1++;
260 while (*s2 == '0')
261 s2++;
262
263 first = 0;
264 while (is_digit(*s1) && is_digit(*s2)) {
265 if (first == 0)
266 first = *s1 - *s2;
267 s1++;
268 s2++;
269 }
270
271 if (is_digit(*s1))
272 return 1;
273 if (is_digit(*s2))
274 return -1;
275
276 if (first != 0)
277 return first;
278 }
279
280 return strcmp(os1, os2);
281}
9ce17593
JK
282
283/* Turn off core dumps but only if we're running outside of a container. */
e557b1a6
LP
284void disable_coredumps(void) {
285 int r;
286
287 if (detect_container() > 0)
288 return;
289
57512c89 290 r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
e557b1a6
LP
291 if (r < 0)
292 log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
9ce17593 293}