Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <alloca.h>
4 : : #include <errno.h>
5 : : #include <fcntl.h>
6 : : #include <sched.h>
7 : : #include <signal.h>
8 : : #include <stdarg.h>
9 : : #include <stdio.h>
10 : : #include <stdlib.h>
11 : : #include <string.h>
12 : : #include <sys/mman.h>
13 : : #include <sys/prctl.h>
14 : : #include <sys/statfs.h>
15 : : #include <sys/sysmacros.h>
16 : : #include <sys/types.h>
17 : : #include <unistd.h>
18 : :
19 : : #include "alloc-util.h"
20 : : #include "btrfs-util.h"
21 : : #include "build.h"
22 : : #include "def.h"
23 : : #include "device-nodes.h"
24 : : #include "dirent-util.h"
25 : : #include "env-file.h"
26 : : #include "env-util.h"
27 : : #include "fd-util.h"
28 : : #include "fileio.h"
29 : : #include "format-util.h"
30 : : #include "hashmap.h"
31 : : #include "hostname-util.h"
32 : : #include "log.h"
33 : : #include "macro.h"
34 : : #include "missing.h"
35 : : #include "parse-util.h"
36 : : #include "path-util.h"
37 : : #include "process-util.h"
38 : : #include "procfs-util.h"
39 : : #include "set.h"
40 : : #include "signal-util.h"
41 : : #include "stat-util.h"
42 : : #include "string-util.h"
43 : : #include "strv.h"
44 : : #include "time-util.h"
45 : : #include "umask-util.h"
46 : : #include "user-util.h"
47 : : #include "util.h"
48 : : #include "virt.h"
49 : :
50 : : int saved_argc = 0;
51 : : char **saved_argv = NULL;
52 : : static int saved_in_initrd = -1;
53 : :
54 : 0 : bool kexec_loaded(void) {
55 : 0 : _cleanup_free_ char *s = NULL;
56 : :
57 [ # # ]: 0 : if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
58 : 0 : return false;
59 : :
60 : 0 : return s[0] == '1';
61 : : }
62 : :
63 : 39372 : int prot_from_flags(int flags) {
64 : :
65 [ + - + - ]: 39372 : switch (flags & O_ACCMODE) {
66 : :
67 : 39268 : case O_RDONLY:
68 : 39268 : return PROT_READ;
69 : :
70 : 0 : case O_WRONLY:
71 : 0 : return PROT_WRITE;
72 : :
73 : 104 : case O_RDWR:
74 : 104 : return PROT_READ|PROT_WRITE;
75 : :
76 : 0 : default:
77 : 0 : return -EINVAL;
78 : : }
79 : : }
80 : :
81 : 5198 : bool in_initrd(void) {
82 : : struct statfs s;
83 : : int r;
84 : :
85 [ + + ]: 5198 : if (saved_in_initrd >= 0)
86 : 3628 : return saved_in_initrd;
87 : :
88 : : /* We make two checks here:
89 : : *
90 : : * 1. the flag file /etc/initrd-release must exist
91 : : * 2. the root file system must be a memory file system
92 : : *
93 : : * The second check is extra paranoia, since misdetecting an
94 : : * initrd can have bad consequences due the initrd
95 : : * emptying when transititioning to the main systemd.
96 : : */
97 : :
98 : 1570 : r = getenv_bool_secure("SYSTEMD_IN_INITRD");
99 [ + - - + ]: 1570 : if (r < 0 && r != -ENXIO)
100 [ # # ]: 0 : log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
101 : :
102 [ - + ]: 1570 : if (r >= 0)
103 : 0 : saved_in_initrd = r > 0;
104 : : else
105 [ # # ]: 3140 : saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
106 [ - + ]: 1570 : statfs("/", &s) >= 0 &&
107 [ # # ]: 0 : is_temporary_fs(&s);
108 : :
109 : 1570 : return saved_in_initrd;
110 : : }
111 : :
112 : 16 : void in_initrd_force(bool value) {
113 : 16 : saved_in_initrd = value;
114 : 16 : }
115 : :
116 : 24 : int on_ac_power(void) {
117 : 24 : bool found_offline = false, found_online = false;
118 : 24 : _cleanup_closedir_ DIR *d = NULL;
119 : : struct dirent *de;
120 : :
121 : 24 : d = opendir("/sys/class/power_supply");
122 [ - + ]: 24 : if (!d)
123 [ # # ]: 0 : return errno == ENOENT ? true : -errno;
124 : :
125 [ - + # # : 120 : FOREACH_DIRENT(de, d, return -errno) {
+ + ]
126 [ - + - + : 144 : _cleanup_close_ int fd = -1, device = -1;
- + - + ]
127 : : char contents[6];
128 : : ssize_t n;
129 : :
130 : 72 : device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
131 [ - + ]: 72 : if (device < 0) {
132 [ # # # # ]: 0 : if (IN_SET(errno, ENOENT, ENOTDIR))
133 : 0 : continue;
134 : :
135 : 0 : return -errno;
136 : : }
137 : :
138 : 72 : fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
139 [ - + ]: 72 : if (fd < 0) {
140 [ # # ]: 0 : if (errno == ENOENT)
141 : 0 : continue;
142 : :
143 : 0 : return -errno;
144 : : }
145 : :
146 : 72 : n = read(fd, contents, sizeof(contents));
147 [ - + ]: 72 : if (n < 0)
148 : 0 : return -errno;
149 : :
150 [ + - + + ]: 72 : if (n != 6 || memcmp(contents, "Mains\n", 6))
151 : 48 : continue;
152 : :
153 : 24 : safe_close(fd);
154 : 24 : fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
155 [ - + ]: 24 : if (fd < 0) {
156 [ # # ]: 0 : if (errno == ENOENT)
157 : 0 : continue;
158 : :
159 : 0 : return -errno;
160 : : }
161 : :
162 : 24 : n = read(fd, contents, sizeof(contents));
163 [ - + ]: 24 : if (n < 0)
164 : 0 : return -errno;
165 : :
166 [ + - - + ]: 24 : if (n != 2 || contents[1] != '\n')
167 : 0 : return -EIO;
168 : :
169 [ + - ]: 24 : if (contents[0] == '1') {
170 : 24 : found_online = true;
171 : 24 : break;
172 [ # # ]: 0 : } else if (contents[0] == '0')
173 : 0 : found_offline = true;
174 : : else
175 : 0 : return -EIO;
176 : : }
177 : :
178 [ - + # # ]: 24 : return found_online || !found_offline;
179 : : }
180 : :
181 : 0 : int container_get_leader(const char *machine, pid_t *pid) {
182 : 0 : _cleanup_free_ char *s = NULL, *class = NULL;
183 : : const char *p;
184 : : pid_t leader;
185 : : int r;
186 : :
187 [ # # ]: 0 : assert(machine);
188 [ # # ]: 0 : assert(pid);
189 : :
190 [ # # ]: 0 : if (streq(machine, ".host")) {
191 : 0 : *pid = 1;
192 : 0 : return 0;
193 : : }
194 : :
195 [ # # ]: 0 : if (!machine_name_is_valid(machine))
196 : 0 : return -EINVAL;
197 : :
198 [ # # # # : 0 : p = strjoina("/run/systemd/machines/", machine);
# # # # #
# # # ]
199 : 0 : r = parse_env_file(NULL, p,
200 : : "LEADER", &s,
201 : : "CLASS", &class);
202 [ # # ]: 0 : if (r == -ENOENT)
203 : 0 : return -EHOSTDOWN;
204 [ # # ]: 0 : if (r < 0)
205 : 0 : return r;
206 [ # # ]: 0 : if (!s)
207 : 0 : return -EIO;
208 : :
209 [ # # ]: 0 : if (!streq_ptr(class, "container"))
210 : 0 : return -EIO;
211 : :
212 : 0 : r = parse_pid(s, &leader);
213 [ # # ]: 0 : if (r < 0)
214 : 0 : return r;
215 [ # # ]: 0 : if (leader <= 1)
216 : 0 : return -EIO;
217 : :
218 : 0 : *pid = leader;
219 : 0 : return 0;
220 : : }
221 : :
222 : 0 : int version(void) {
223 : 0 : puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
224 : : SYSTEMD_FEATURES);
225 : 0 : return 0;
226 : : }
227 : :
228 : : /* This is a direct translation of str_verscmp from boot.c */
229 : 2088 : static bool is_digit(int c) {
230 [ + + + + ]: 2088 : return c >= '0' && c <= '9';
231 : : }
232 : :
233 : 360 : static int c_order(int c) {
234 [ + - - + ]: 360 : if (c == 0 || is_digit(c))
235 : 0 : return 0;
236 : :
237 [ + + + - ]: 360 : if ((c >= 'a') && (c <= 'z'))
238 : 120 : return c;
239 : :
240 : 240 : return c + 0x10000;
241 : : }
242 : :
243 : 76 : int str_verscmp(const char *s1, const char *s2) {
244 : : const char *os1, *os2;
245 : :
246 [ - + ]: 76 : assert(s1);
247 [ - + ]: 76 : assert(s2);
248 : :
249 : 76 : os1 = s1;
250 : 76 : os2 = s2;
251 : :
252 [ + + - + ]: 216 : while (*s1 || *s2) {
253 : : int first;
254 : :
255 [ + - + + : 376 : while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
+ - - + ]
256 : : int order;
257 : :
258 : 180 : order = c_order(*s1) - c_order(*s2);
259 [ - + ]: 180 : if (order != 0)
260 : 0 : return order;
261 : 180 : s1++;
262 : 180 : s2++;
263 : : }
264 : :
265 [ - + ]: 196 : while (*s1 == '0')
266 : 0 : s1++;
267 [ + + ]: 228 : while (*s2 == '0')
268 : 32 : s2++;
269 : :
270 : 196 : first = 0;
271 [ + + + + ]: 480 : while (is_digit(*s1) && is_digit(*s2)) {
272 [ + - ]: 284 : if (first == 0)
273 : 284 : first = *s1 - *s2;
274 : 284 : s1++;
275 : 284 : s2++;
276 : : }
277 : :
278 [ + + ]: 196 : if (is_digit(*s1))
279 : 32 : return 1;
280 [ + + ]: 164 : if (is_digit(*s2))
281 : 20 : return -1;
282 : :
283 [ + + ]: 144 : if (first != 0)
284 : 4 : return first;
285 : : }
286 : :
287 : 20 : return strcmp(os1, os2);
288 : : }
289 : :
290 : : /* Turn off core dumps but only if we're running outside of a container. */
291 : 0 : void disable_coredumps(void) {
292 : : int r;
293 : :
294 [ # # ]: 0 : if (detect_container() > 0)
295 : 0 : return;
296 : :
297 : 0 : r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
298 [ # # ]: 0 : if (r < 0)
299 [ # # ]: 0 : log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
300 : : }
|