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 9843 : int prot_from_flags(int flags) {
64 :
65 9843 : switch (flags & O_ACCMODE) {
66 :
67 9817 : case O_RDONLY:
68 9817 : return PROT_READ;
69 :
70 0 : case O_WRONLY:
71 0 : return PROT_WRITE;
72 :
73 26 : case O_RDWR:
74 26 : return PROT_READ|PROT_WRITE;
75 :
76 0 : default:
77 0 : return -EINVAL;
78 : }
79 : }
80 :
81 1301 : bool in_initrd(void) {
82 : struct statfs s;
83 : int r;
84 :
85 1301 : if (saved_in_initrd >= 0)
86 908 : 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 393 : r = getenv_bool_secure("SYSTEMD_IN_INITRD");
99 393 : if (r < 0 && r != -ENXIO)
100 0 : log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
101 :
102 393 : if (r >= 0)
103 0 : saved_in_initrd = r > 0;
104 : else
105 786 : saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
106 393 : statfs("/", &s) >= 0 &&
107 0 : is_temporary_fs(&s);
108 :
109 393 : return saved_in_initrd;
110 : }
111 :
112 4 : void in_initrd_force(bool value) {
113 4 : saved_in_initrd = value;
114 4 : }
115 :
116 6 : int on_ac_power(void) {
117 6 : bool found_offline = false, found_online = false;
118 6 : _cleanup_closedir_ DIR *d = NULL;
119 : struct dirent *de;
120 :
121 6 : d = opendir("/sys/class/power_supply");
122 6 : if (!d)
123 0 : return errno == ENOENT ? true : -errno;
124 :
125 30 : FOREACH_DIRENT(de, d, return -errno) {
126 36 : _cleanup_close_ int fd = -1, device = -1;
127 : char contents[6];
128 : ssize_t n;
129 :
130 18 : device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
131 18 : if (device < 0) {
132 0 : if (IN_SET(errno, ENOENT, ENOTDIR))
133 0 : continue;
134 :
135 0 : return -errno;
136 : }
137 :
138 18 : fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
139 18 : if (fd < 0) {
140 0 : if (errno == ENOENT)
141 0 : continue;
142 :
143 0 : return -errno;
144 : }
145 :
146 18 : n = read(fd, contents, sizeof(contents));
147 18 : if (n < 0)
148 0 : return -errno;
149 :
150 18 : if (n != 6 || memcmp(contents, "Mains\n", 6))
151 12 : continue;
152 :
153 6 : safe_close(fd);
154 6 : fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
155 6 : if (fd < 0) {
156 0 : if (errno == ENOENT)
157 0 : continue;
158 :
159 0 : return -errno;
160 : }
161 :
162 6 : n = read(fd, contents, sizeof(contents));
163 6 : if (n < 0)
164 0 : return -errno;
165 :
166 6 : if (n != 2 || contents[1] != '\n')
167 0 : return -EIO;
168 :
169 6 : if (contents[0] == '1') {
170 6 : found_online = true;
171 6 : break;
172 0 : } else if (contents[0] == '0')
173 0 : found_offline = true;
174 : else
175 0 : return -EIO;
176 : }
177 :
178 6 : 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 522 : static bool is_digit(int c) {
230 522 : return c >= '0' && c <= '9';
231 : }
232 :
233 90 : static int c_order(int c) {
234 90 : if (c == 0 || is_digit(c))
235 0 : return 0;
236 :
237 90 : if ((c >= 'a') && (c <= 'z'))
238 30 : return c;
239 :
240 60 : return c + 0x10000;
241 : }
242 :
243 19 : int str_verscmp(const char *s1, const char *s2) {
244 : const char *os1, *os2;
245 :
246 19 : assert(s1);
247 19 : assert(s2);
248 :
249 19 : os1 = s1;
250 19 : os2 = s2;
251 :
252 54 : while (*s1 || *s2) {
253 : int first;
254 :
255 94 : while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
256 : int order;
257 :
258 45 : order = c_order(*s1) - c_order(*s2);
259 45 : if (order != 0)
260 0 : return order;
261 45 : s1++;
262 45 : s2++;
263 : }
264 :
265 49 : while (*s1 == '0')
266 0 : s1++;
267 57 : while (*s2 == '0')
268 8 : s2++;
269 :
270 49 : first = 0;
271 120 : while (is_digit(*s1) && is_digit(*s2)) {
272 71 : if (first == 0)
273 71 : first = *s1 - *s2;
274 71 : s1++;
275 71 : s2++;
276 : }
277 :
278 49 : if (is_digit(*s1))
279 8 : return 1;
280 41 : if (is_digit(*s2))
281 5 : return -1;
282 :
283 36 : if (first != 0)
284 1 : return first;
285 : }
286 :
287 5 : 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 : }
|