]> git.proxmox.com Git - systemd.git/blob - src/basic/util.c
New upstream version 242
[systemd.git] / src / basic / util.c
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 bool kexec_loaded(void) {
55 _cleanup_free_ char *s = NULL;
56
57 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
58 return false;
59
60 return s[0] == '1';
61 }
62
63 int prot_from_flags(int flags) {
64
65 switch (flags & O_ACCMODE) {
66
67 case O_RDONLY:
68 return PROT_READ;
69
70 case O_WRONLY:
71 return PROT_WRITE;
72
73 case O_RDWR:
74 return PROT_READ|PROT_WRITE;
75
76 default:
77 return -EINVAL;
78 }
79 }
80
81 bool in_initrd(void) {
82 struct statfs s;
83 int r;
84
85 if (saved_in_initrd >= 0)
86 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 r = getenv_bool_secure("SYSTEMD_IN_INITRD");
99 if (r < 0 && r != -ENXIO)
100 log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
101
102 if (r >= 0)
103 saved_in_initrd = r > 0;
104 else
105 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
106 statfs("/", &s) >= 0 &&
107 is_temporary_fs(&s);
108
109 return saved_in_initrd;
110 }
111
112 void in_initrd_force(bool value) {
113 saved_in_initrd = value;
114 }
115
116 int on_ac_power(void) {
117 bool found_offline = false, found_online = false;
118 _cleanup_closedir_ DIR *d = NULL;
119 struct dirent *de;
120
121 d = opendir("/sys/class/power_supply");
122 if (!d)
123 return errno == ENOENT ? true : -errno;
124
125 FOREACH_DIRENT(de, d, return -errno) {
126 _cleanup_close_ int fd = -1, device = -1;
127 char contents[6];
128 ssize_t n;
129
130 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
131 if (device < 0) {
132 if (IN_SET(errno, ENOENT, ENOTDIR))
133 continue;
134
135 return -errno;
136 }
137
138 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
139 if (fd < 0) {
140 if (errno == ENOENT)
141 continue;
142
143 return -errno;
144 }
145
146 n = read(fd, contents, sizeof(contents));
147 if (n < 0)
148 return -errno;
149
150 if (n != 6 || memcmp(contents, "Mains\n", 6))
151 continue;
152
153 safe_close(fd);
154 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
155 if (fd < 0) {
156 if (errno == ENOENT)
157 continue;
158
159 return -errno;
160 }
161
162 n = read(fd, contents, sizeof(contents));
163 if (n < 0)
164 return -errno;
165
166 if (n != 2 || contents[1] != '\n')
167 return -EIO;
168
169 if (contents[0] == '1') {
170 found_online = true;
171 break;
172 } else if (contents[0] == '0')
173 found_offline = true;
174 else
175 return -EIO;
176 }
177
178 return found_online || !found_offline;
179 }
180
181 int container_get_leader(const char *machine, pid_t *pid) {
182 _cleanup_free_ char *s = NULL, *class = NULL;
183 const char *p;
184 pid_t leader;
185 int r;
186
187 assert(machine);
188 assert(pid);
189
190 if (streq(machine, ".host")) {
191 *pid = 1;
192 return 0;
193 }
194
195 if (!machine_name_is_valid(machine))
196 return -EINVAL;
197
198 p = strjoina("/run/systemd/machines/", machine);
199 r = parse_env_file(NULL, p,
200 "LEADER", &s,
201 "CLASS", &class);
202 if (r == -ENOENT)
203 return -EHOSTDOWN;
204 if (r < 0)
205 return r;
206 if (!s)
207 return -EIO;
208
209 if (!streq_ptr(class, "container"))
210 return -EIO;
211
212 r = parse_pid(s, &leader);
213 if (r < 0)
214 return r;
215 if (leader <= 1)
216 return -EIO;
217
218 *pid = leader;
219 return 0;
220 }
221
222 int version(void) {
223 puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
224 SYSTEMD_FEATURES);
225 return 0;
226 }
227
228 /* This is a direct translation of str_verscmp from boot.c */
229 static bool is_digit(int c) {
230 return c >= '0' && c <= '9';
231 }
232
233 static int c_order(int c) {
234 if (c == 0 || is_digit(c))
235 return 0;
236
237 if ((c >= 'a') && (c <= 'z'))
238 return c;
239
240 return c + 0x10000;
241 }
242
243 int str_verscmp(const char *s1, const char *s2) {
244 const char *os1, *os2;
245
246 assert(s1);
247 assert(s2);
248
249 os1 = s1;
250 os2 = s2;
251
252 while (*s1 || *s2) {
253 int first;
254
255 while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
256 int order;
257
258 order = c_order(*s1) - c_order(*s2);
259 if (order != 0)
260 return order;
261 s1++;
262 s2++;
263 }
264
265 while (*s1 == '0')
266 s1++;
267 while (*s2 == '0')
268 s2++;
269
270 first = 0;
271 while (is_digit(*s1) && is_digit(*s2)) {
272 if (first == 0)
273 first = *s1 - *s2;
274 s1++;
275 s2++;
276 }
277
278 if (is_digit(*s1))
279 return 1;
280 if (is_digit(*s2))
281 return -1;
282
283 if (first != 0)
284 return first;
285 }
286
287 return strcmp(os1, os2);
288 }
289
290 /* Turn off core dumps but only if we're running outside of a container. */
291 void disable_coredumps(void) {
292 int r;
293
294 if (detect_container() > 0)
295 return;
296
297 r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
298 if (r < 0)
299 log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
300 }