1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 //#include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/statfs.h>
33 #include <sys/sysmacros.h>
34 //#include <sys/types.h>
37 #include "alloc-util.h"
38 //#include "btrfs-util.h"
40 #include "cgroup-util.h"
42 //#include "device-nodes.h"
43 #include "dirent-util.h"
46 //#include "format-util.h"
48 #include "hostname-util.h"
51 //#include "missing.h"
52 #include "parse-util.h"
53 //#include "path-util.h"
54 #include "process-util.h"
55 //#include "procfs-util.h"
57 #include "signal-util.h"
58 #include "stat-util.h"
59 #include "string-util.h"
61 #include "time-util.h"
62 #include "umask-util.h"
63 #include "user-util.h"
68 char **saved_argv = NULL;
69 static int saved_in_initrd = -1;
71 size_t page_size(void) {
72 static thread_local size_t pgsz = 0;
75 if (_likely_(pgsz > 0))
78 r = sysconf(_SC_PAGESIZE);
85 #if 0 /// UNNEEDED by elogind
86 bool plymouth_running(void) {
87 return access("/run/plymouth/pid", F_OK) >= 0;
91 bool display_is_local(const char *display) {
100 int socket_from_display(const char *display, char **path) {
107 if (!display_is_local(display))
110 k = strspn(display+1, "0123456789");
112 f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
116 c = stpcpy(f, "/tmp/.X11-unix/X");
117 memcpy(c, display+1, k);
125 #if 0 /// UNNEEDED by elogind
126 bool kexec_loaded(void) {
127 _cleanup_free_ char *s = NULL;
129 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
135 int prot_from_flags(int flags) {
137 switch (flags & O_ACCMODE) {
146 return PROT_READ|PROT_WRITE;
154 bool in_initrd(void) {
157 if (saved_in_initrd >= 0)
158 return saved_in_initrd;
160 /* We make two checks here:
162 * 1. the flag file /etc/initrd-release must exist
163 * 2. the root file system must be a memory file system
165 * The second check is extra paranoia, since misdetecting an
166 * initrd can have bad consequences due the initrd
167 * emptying when transititioning to the main systemd.
170 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
171 statfs("/", &s) >= 0 &&
174 return saved_in_initrd;
177 void in_initrd_force(bool value) {
178 saved_in_initrd = value;
181 #if 0 /// UNNEEDED by elogind
182 /* hey glibc, APIs with callbacks without a user pointer are so useless */
183 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
184 int (*compar) (const void *, const void *, void *), void *arg) {
193 p = (const char *) base + idx * size;
194 comparison = compar(key, p, arg);
197 else if (comparison > 0)
205 int on_ac_power(void) {
206 bool found_offline = false, found_online = false;
207 _cleanup_closedir_ DIR *d = NULL;
210 d = opendir("/sys/class/power_supply");
212 return errno == ENOENT ? true : -errno;
214 FOREACH_DIRENT(de, d, return -errno) {
215 _cleanup_close_ int fd = -1, device = -1;
219 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
221 if (IN_SET(errno, ENOENT, ENOTDIR))
227 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
235 n = read(fd, contents, sizeof(contents));
239 if (n != 6 || memcmp(contents, "Mains\n", 6))
243 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
251 n = read(fd, contents, sizeof(contents));
255 if (n != 2 || contents[1] != '\n')
258 if (contents[0] == '1') {
261 } else if (contents[0] == '0')
262 found_offline = true;
267 return found_online || !found_offline;
271 int container_get_leader(const char *machine, pid_t *pid) {
272 _cleanup_free_ char *s = NULL, *class = NULL;
280 if (!machine_name_is_valid(machine))
283 p = strjoina("/run/systemd/machines/", machine);
284 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
292 if (!streq_ptr(class, "container"))
295 r = parse_pid(s, &leader);
305 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
306 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
314 mntns = procfs_file_alloca(pid, "ns/mnt");
315 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
323 pidns = procfs_file_alloca(pid, "ns/pid");
324 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
332 netns = procfs_file_alloca(pid, "ns/net");
333 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
341 userns = procfs_file_alloca(pid, "ns/user");
342 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
343 if (usernsfd < 0 && errno != ENOENT)
350 root = procfs_file_alloca(pid, "root");
351 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
366 *userns_fd = usernsfd;
371 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
376 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
377 if (userns_fd >= 0) {
378 /* Can't setns to your own userns, since then you could
379 * escalate from non-root to root in your own namespace, so
380 * check if namespaces equal before attempting to enter. */
381 _cleanup_free_ char *userns_fd_path = NULL;
383 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
386 r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
394 if (setns(pidns_fd, CLONE_NEWPID) < 0)
398 if (setns(mntns_fd, CLONE_NEWNS) < 0)
402 if (setns(netns_fd, CLONE_NEWNET) < 0)
406 if (setns(userns_fd, CLONE_NEWUSER) < 0)
410 if (fchdir(root_fd) < 0)
417 return reset_uid_gid();
420 uint64_t physical_memory(void) {
421 _cleanup_free_ char *root = NULL, *value = NULL;
426 /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
429 * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
430 * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
432 sc = sysconf(_SC_PHYS_PAGES);
436 mem = (uint64_t) sc * (uint64_t) ps;
438 if (cg_get_root_path(&root) < 0)
441 if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value))
444 if (safe_atou64(value, &lim) < 0)
447 /* Make sure the limit is a multiple of our own page size */
451 return MIN(mem, lim);
454 uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
455 uint64_t p, m, ps, r;
459 /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
460 * the result is a multiple of the page size (rounds down). */
465 p = physical_memory() / ps;
481 uint64_t system_tasks_max(void) {
484 uint64_t a = TASKS_MAX, b = TASKS_MAX;
485 _cleanup_free_ char *root = NULL;
487 /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
490 * a) the maximum tasks value the kernel allows on this architecture
491 * b) the cgroups pids_max attribute for the system
492 * c) the kernel's configured maximum PID value
494 * And then pick the smallest of the three */
496 (void) procfs_tasks_get_limit(&a);
498 if (cg_get_root_path(&root) >= 0) {
499 _cleanup_free_ char *value = NULL;
501 if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
502 (void) safe_atou64(value, &b);
505 return MIN3(TASKS_MAX,
506 a <= 0 ? TASKS_MAX : a,
507 b <= 0 ? TASKS_MAX : b);
510 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
515 /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
516 * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
518 t = system_tasks_max();
522 if (m / t != v) /* overflow? */
528 #if 0 /// UNNEEDED by elogind
529 int update_reboot_parameter_and_warn(const char *param) {
532 if (isempty(param)) {
533 if (unlink("/run/systemd/reboot-param") < 0) {
537 return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
543 RUN_WITH_UMASK(0022) {
544 r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
546 return log_warning_errno(r, "Failed to write reboot parameter file: %m");
554 puts(PACKAGE_STRING "\n"
559 #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");