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