1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2010 Lennart Poettering
15 //#include <sys/mman.h>
16 #include <sys/prctl.h>
17 #include <sys/statfs.h>
18 #include <sys/sysmacros.h>
19 //#include <sys/types.h>
22 #include "alloc-util.h"
23 //#include "btrfs-util.h"
25 #include "cgroup-util.h"
27 //#include "device-nodes.h"
28 #include "dirent-util.h"
31 //#include "format-util.h"
33 #include "hostname-util.h"
36 //#include "missing.h"
37 #include "parse-util.h"
38 //#include "path-util.h"
39 #include "process-util.h"
40 #include "procfs-util.h"
42 #include "signal-util.h"
43 #include "stat-util.h"
44 #include "string-util.h"
46 #include "time-util.h"
47 #include "umask-util.h"
48 #include "user-util.h"
53 char **saved_argv = NULL;
54 static int saved_in_initrd = -1;
56 size_t page_size(void) {
57 static thread_local size_t pgsz = 0;
60 if (_likely_(pgsz > 0))
63 r = sysconf(_SC_PAGESIZE);
70 #if 0 /// UNNEEDED by elogind
71 bool plymouth_running(void) {
72 return access("/run/plymouth/pid", F_OK) >= 0;
76 bool display_is_local(const char *display) {
85 int socket_from_display(const char *display, char **path) {
92 if (!display_is_local(display))
95 k = strspn(display+1, "0123456789");
97 f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
101 c = stpcpy(f, "/tmp/.X11-unix/X");
102 memcpy(c, display+1, k);
110 #if 0 /// UNNEEDED by elogind
111 bool kexec_loaded(void) {
112 _cleanup_free_ char *s = NULL;
114 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
120 int prot_from_flags(int flags) {
122 switch (flags & O_ACCMODE) {
131 return PROT_READ|PROT_WRITE;
139 bool in_initrd(void) {
142 if (saved_in_initrd >= 0)
143 return saved_in_initrd;
145 /* We make two checks here:
147 * 1. the flag file /etc/initrd-release must exist
148 * 2. the root file system must be a memory file system
150 * The second check is extra paranoia, since misdetecting an
151 * initrd can have bad consequences due the initrd
152 * emptying when transititioning to the main systemd.
155 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
156 statfs("/", &s) >= 0 &&
159 return saved_in_initrd;
162 #if 0 /// UNNEEDED by elogind
163 void in_initrd_force(bool value) {
164 saved_in_initrd = value;
167 /* hey glibc, APIs with callbacks without a user pointer are so useless */
168 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
169 int (*compar) (const void *, const void *, void *), void *arg) {
174 assert(!size_multiply_overflow(nmemb, size));
180 p = (const uint8_t*) base + idx * size;
181 comparison = compar(key, p, arg);
184 else if (comparison > 0)
193 int on_ac_power(void) {
194 bool found_offline = false, found_online = false;
195 _cleanup_closedir_ DIR *d = NULL;
198 d = opendir("/sys/class/power_supply");
200 return errno == ENOENT ? true : -errno;
202 FOREACH_DIRENT(de, d, return -errno) {
203 _cleanup_close_ int fd = -1, device = -1;
207 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
209 if (IN_SET(errno, ENOENT, ENOTDIR))
215 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
223 n = read(fd, contents, sizeof(contents));
227 if (n != 6 || memcmp(contents, "Mains\n", 6))
231 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
239 n = read(fd, contents, sizeof(contents));
243 if (n != 2 || contents[1] != '\n')
246 if (contents[0] == '1') {
249 } else if (contents[0] == '0')
250 found_offline = true;
255 return found_online || !found_offline;
258 int container_get_leader(const char *machine, pid_t *pid) {
259 _cleanup_free_ char *s = NULL, *class = NULL;
267 if (!machine_name_is_valid(machine))
270 p = strjoina("/run/systemd/machines/", machine);
271 r = parse_env_file(NULL, p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
279 if (!streq_ptr(class, "container"))
282 r = parse_pid(s, &leader);
292 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
293 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
301 mntns = procfs_file_alloca(pid, "ns/mnt");
302 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
310 pidns = procfs_file_alloca(pid, "ns/pid");
311 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
319 netns = procfs_file_alloca(pid, "ns/net");
320 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
328 userns = procfs_file_alloca(pid, "ns/user");
329 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
330 if (usernsfd < 0 && errno != ENOENT)
337 root = procfs_file_alloca(pid, "root");
338 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
353 *userns_fd = usernsfd;
358 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
363 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
364 if (userns_fd >= 0) {
365 /* Can't setns to your own userns, since then you could
366 * escalate from non-root to root in your own namespace, so
367 * check if namespaces equal before attempting to enter. */
368 _cleanup_free_ char *userns_fd_path = NULL;
370 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
373 r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
381 if (setns(pidns_fd, CLONE_NEWPID) < 0)
385 if (setns(mntns_fd, CLONE_NEWNS) < 0)
389 if (setns(netns_fd, CLONE_NEWNET) < 0)
393 if (setns(userns_fd, CLONE_NEWUSER) < 0)
397 if (fchdir(root_fd) < 0)
404 return reset_uid_gid();
407 uint64_t physical_memory(void) {
408 _cleanup_free_ char *root = NULL, *value = NULL;
414 /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
417 * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
418 * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
420 sc = sysconf(_SC_PHYS_PAGES);
424 mem = (uint64_t) sc * (uint64_t) ps;
426 r = cg_get_root_path(&root);
428 log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
432 r = cg_all_unified();
434 log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
438 r = cg_get_attribute("memory", root, "memory.max", &value);
440 log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
444 if (streq(value, "max"))
447 r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
449 log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
454 r = safe_atou64(value, &lim);
456 log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
459 if (lim == UINT64_MAX)
462 /* Make sure the limit is a multiple of our own page size */
466 return MIN(mem, lim);
469 uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
470 uint64_t p, m, ps, r;
474 /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
475 * the result is a multiple of the page size (rounds down). */
480 p = physical_memory() / ps;
496 uint64_t system_tasks_max(void) {
498 uint64_t a = TASKS_MAX, b = TASKS_MAX;
499 _cleanup_free_ char *root = NULL;
502 /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
505 * a) the maximum tasks value the kernel allows on this architecture
506 * b) the cgroups pids_max attribute for the system
507 * c) the kernel's configured maximum PID value
509 * And then pick the smallest of the three */
511 r = procfs_tasks_get_limit(&a);
513 log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
515 r = cg_get_root_path(&root);
517 log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
519 _cleanup_free_ char *value = NULL;
521 r = cg_get_attribute("pids", root, "pids.max", &value);
523 log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
524 else if (!streq(value, "max")) {
525 r = safe_atou64(value, &b);
527 log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
531 return MIN3(TASKS_MAX,
532 a <= 0 ? TASKS_MAX : a,
533 b <= 0 ? TASKS_MAX : b);
536 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
541 /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
542 * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
544 t = system_tasks_max();
548 if (m / t != v) /* overflow? */
555 puts(PACKAGE_STRING "\n"
560 #if 0 /// UNNEEDED by elogind
561 /* This is a direct translation of str_verscmp from boot.c */
562 static bool is_digit(int c) {
563 return c >= '0' && c <= '9';
566 static int c_order(int c) {
567 if (c == 0 || is_digit(c))
570 if ((c >= 'a') && (c <= 'z'))
576 int str_verscmp(const char *s1, const char *s2) {
577 const char *os1, *os2;
588 while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
591 order = c_order(*s1) - c_order(*s2);
604 while (is_digit(*s1) && is_digit(*s2)) {
620 return strcmp(os1, os2);
623 /* Turn off core dumps but only if we're running outside of a container. */
624 void disable_coredumps(void) {
627 if (detect_container() > 0)
630 r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
632 log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");