]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/util.c
util: split out memcmp()/memset() related calls into memory-util.[ch]
[thirdparty/systemd.git] / src / basic / util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09 2
11c3a366 3#include <alloca.h>
60918275 4#include <errno.h>
f6c2284a 5#include <fcntl.h>
f6c2284a
LP
6#include <sched.h>
7#include <signal.h>
8#include <stdarg.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
87d2c1ff 12#include <sys/mman.h>
f6c2284a 13#include <sys/prctl.h>
11c3a366
TA
14#include <sys/statfs.h>
15#include <sys/sysmacros.h>
f6c2284a 16#include <sys/types.h>
f6c2284a 17#include <unistd.h>
eef46c37 18
b5efdb8a 19#include "alloc-util.h"
c43b2b9c 20#include "btrfs-util.h"
3f6fd1ba 21#include "build.h"
f6c2284a 22#include "def.h"
553e15f2 23#include "device-nodes.h"
cf0fbc49 24#include "dirent-util.h"
686d13b9 25#include "env-file.h"
0307ea49 26#include "env-util.h"
3ffd4af2 27#include "fd-util.h"
f6c2284a 28#include "fileio.h"
f97b34a6 29#include "format-util.h"
f6c2284a
LP
30#include "hashmap.h"
31#include "hostname-util.h"
a9f5d454 32#include "log.h"
f6c2284a
LP
33#include "macro.h"
34#include "missing.h"
6bedfcbb 35#include "parse-util.h"
9eb977db 36#include "path-util.h"
0b452006 37#include "process-util.h"
1e7da35b 38#include "procfs-util.h"
11c3a366 39#include "set.h"
93cc7779 40#include "signal-util.h"
cf0fbc49 41#include "stat-util.h"
07630cea 42#include "string-util.h"
f6c2284a 43#include "strv.h"
93cc7779 44#include "time-util.h"
8612da97 45#include "umask-util.h"
b1d4f8e1 46#include "user-util.h"
4f5dd394 47#include "util.h"
9ce17593 48#include "virt.h"
56cf987f 49
9a0e6896
LP
50int saved_argc = 0;
51char **saved_argv = NULL;
dcd61450 52static int saved_in_initrd = -1;
9086e840 53
a88c8750
TG
54bool plymouth_running(void) {
55 return access("/run/plymouth/pid", F_OK) >= 0;
56}
57
4d6d6518
LP
58bool display_is_local(const char *display) {
59 assert(display);
60
61 return
62 display[0] == ':' &&
63 display[1] >= '0' &&
64 display[1] <= '9';
65}
66
65457142 67bool kexec_loaded(void) {
c47f86e6
ZJS
68 _cleanup_free_ char *s = NULL;
69
70 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
71 return false;
72
73 return s[0] == '1';
65457142 74}
fb9de93d 75
87d2c1ff
LP
76int prot_from_flags(int flags) {
77
78 switch (flags & O_ACCMODE) {
79
80 case O_RDONLY:
81 return PROT_READ;
82
83 case O_WRONLY:
84 return PROT_WRITE;
85
86 case O_RDWR:
87 return PROT_READ|PROT_WRITE;
88
89 default:
90 return -EINVAL;
91 }
7c99e0c1 92}
689b9a22 93
9be346c9 94bool in_initrd(void) {
825c6fe5 95 struct statfs s;
0307ea49 96 int r;
8f33b5b8 97
dcd61450
IS
98 if (saved_in_initrd >= 0)
99 return saved_in_initrd;
825c6fe5
LP
100
101 /* We make two checks here:
102 *
103 * 1. the flag file /etc/initrd-release must exist
104 * 2. the root file system must be a memory file system
105 *
106 * The second check is extra paranoia, since misdetecting an
629ff674 107 * initrd can have bad consequences due the initrd
825c6fe5
LP
108 * emptying when transititioning to the main systemd.
109 */
110
0307ea49
ZJS
111 r = getenv_bool_secure("SYSTEMD_IN_INITRD");
112 if (r < 0 && r != -ENXIO)
113 log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
114
115 if (r >= 0)
116 saved_in_initrd = r > 0;
117 else
118 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
119 statfs("/", &s) >= 0 &&
120 is_temporary_fs(&s);
9be346c9 121
dcd61450
IS
122 return saved_in_initrd;
123}
124
125void in_initrd_force(bool value) {
126 saved_in_initrd = value;
9be346c9 127}
069cfc85 128
a9e12476
KS
129/* hey glibc, APIs with callbacks without a user pointer are so useless */
130void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
f0f6d791 131 __compar_d_fn_t compar, void *arg) {
a9e12476
KS
132 size_t l, u, idx;
133 const void *p;
134 int comparison;
135
2901f4b3
LP
136 assert(!size_multiply_overflow(nmemb, size));
137
a9e12476
KS
138 l = 0;
139 u = nmemb;
140 while (l < u) {
141 idx = (l + u) / 2;
2901f4b3 142 p = (const uint8_t*) base + idx * size;
a9e12476
KS
143 comparison = compar(key, p, arg);
144 if (comparison < 0)
145 u = idx;
146 else if (comparison > 0)
147 l = idx + 1;
148 else
149 return (void *)p;
150 }
151 return NULL;
152}
09017585 153
240dbaa4
LP
154int on_ac_power(void) {
155 bool found_offline = false, found_online = false;
156 _cleanup_closedir_ DIR *d = NULL;
8fb3f009 157 struct dirent *de;
240dbaa4
LP
158
159 d = opendir("/sys/class/power_supply");
160 if (!d)
6d890034 161 return errno == ENOENT ? true : -errno;
240dbaa4 162
8fb3f009 163 FOREACH_DIRENT(de, d, return -errno) {
240dbaa4
LP
164 _cleanup_close_ int fd = -1, device = -1;
165 char contents[6];
166 ssize_t n;
240dbaa4 167
240dbaa4
LP
168 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
169 if (device < 0) {
3742095b 170 if (IN_SET(errno, ENOENT, ENOTDIR))
240dbaa4
LP
171 continue;
172
173 return -errno;
174 }
175
176 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
177 if (fd < 0) {
178 if (errno == ENOENT)
179 continue;
180
181 return -errno;
182 }
183
184 n = read(fd, contents, sizeof(contents));
185 if (n < 0)
186 return -errno;
187
188 if (n != 6 || memcmp(contents, "Mains\n", 6))
189 continue;
190
03e334a1 191 safe_close(fd);
240dbaa4
LP
192 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
193 if (fd < 0) {
194 if (errno == ENOENT)
195 continue;
196
197 return -errno;
198 }
199
200 n = read(fd, contents, sizeof(contents));
201 if (n < 0)
202 return -errno;
203
204 if (n != 2 || contents[1] != '\n')
205 return -EIO;
206
207 if (contents[0] == '1') {
208 found_online = true;
209 break;
210 } else if (contents[0] == '0')
211 found_offline = true;
212 else
213 return -EIO;
214 }
215
216 return found_online || !found_offline;
217}
fabe5c0e 218
bc9fd78c
LP
219int container_get_leader(const char *machine, pid_t *pid) {
220 _cleanup_free_ char *s = NULL, *class = NULL;
221 const char *p;
222 pid_t leader;
223 int r;
224
225 assert(machine);
226 assert(pid);
227
1e5057b9
LP
228 if (streq(machine, ".host")) {
229 *pid = 1;
230 return 0;
231 }
232
b9a8d250
LP
233 if (!machine_name_is_valid(machine))
234 return -EINVAL;
235
63c372cb 236 p = strjoina("/run/systemd/machines/", machine);
13df9c39
LP
237 r = parse_env_file(NULL, p,
238 "LEADER", &s,
239 "CLASS", &class);
bc9fd78c
LP
240 if (r == -ENOENT)
241 return -EHOSTDOWN;
242 if (r < 0)
243 return r;
244 if (!s)
245 return -EIO;
246
247 if (!streq_ptr(class, "container"))
248 return -EIO;
249
250 r = parse_pid(s, &leader);
251 if (r < 0)
252 return r;
253 if (leader <= 1)
254 return -EIO;
255
256 *pid = leader;
257 return 0;
258}
259
3f6fd1ba 260int version(void) {
f1028f57 261 puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
3f6fd1ba
LP
262 SYSTEMD_FEATURES);
263 return 0;
264}
68c58c67
LP
265
266/* This is a direct translation of str_verscmp from boot.c */
267static bool is_digit(int c) {
268 return c >= '0' && c <= '9';
269}
270
271static int c_order(int c) {
272 if (c == 0 || is_digit(c))
273 return 0;
274
275 if ((c >= 'a') && (c <= 'z'))
276 return c;
277
278 return c + 0x10000;
279}
280
281int str_verscmp(const char *s1, const char *s2) {
282 const char *os1, *os2;
283
284 assert(s1);
285 assert(s2);
286
287 os1 = s1;
288 os2 = s2;
289
290 while (*s1 || *s2) {
291 int first;
292
293 while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
294 int order;
295
296 order = c_order(*s1) - c_order(*s2);
297 if (order != 0)
298 return order;
299 s1++;
300 s2++;
301 }
302
303 while (*s1 == '0')
304 s1++;
305 while (*s2 == '0')
306 s2++;
307
308 first = 0;
309 while (is_digit(*s1) && is_digit(*s2)) {
310 if (first == 0)
311 first = *s1 - *s2;
312 s1++;
313 s2++;
314 }
315
316 if (is_digit(*s1))
317 return 1;
318 if (is_digit(*s2))
319 return -1;
320
321 if (first != 0)
322 return first;
323 }
324
325 return strcmp(os1, os2);
326}
9ce17593
JK
327
328/* Turn off core dumps but only if we're running outside of a container. */
e557b1a6
LP
329void disable_coredumps(void) {
330 int r;
331
332 if (detect_container() > 0)
333 return;
334
57512c89 335 r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
e557b1a6
LP
336 if (r < 0)
337 log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
9ce17593 338}