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"
56 #include "signal-util.h"
57 #include "stat-util.h"
58 #include "string-util.h"
60 #include "time-util.h"
61 #include "umask-util.h"
62 #include "user-util.h"
66 char **saved_argv = NULL;
67 static int saved_in_initrd = -1;
69 size_t page_size(void) {
70 static thread_local size_t pgsz = 0;
73 if (_likely_(pgsz > 0))
76 r = sysconf(_SC_PAGESIZE);
83 #if 0 /// UNNEEDED by elogind
84 bool plymouth_running(void) {
85 return access("/run/plymouth/pid", F_OK) >= 0;
89 bool display_is_local(const char *display) {
98 int socket_from_display(const char *display, char **path) {
105 if (!display_is_local(display))
108 k = strspn(display+1, "0123456789");
110 f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
114 c = stpcpy(f, "/tmp/.X11-unix/X");
115 memcpy(c, display+1, k);
123 #if 0 /// UNNEEDED by elogind
124 bool kexec_loaded(void) {
125 _cleanup_free_ char *s = NULL;
127 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
133 int prot_from_flags(int flags) {
135 switch (flags & O_ACCMODE) {
144 return PROT_READ|PROT_WRITE;
152 bool in_initrd(void) {
155 if (saved_in_initrd >= 0)
156 return saved_in_initrd;
158 /* We make two checks here:
160 * 1. the flag file /etc/initrd-release must exist
161 * 2. the root file system must be a memory file system
163 * The second check is extra paranoia, since misdetecting an
164 * initrd can have bad consequences due the initrd
165 * emptying when transititioning to the main systemd.
168 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
169 statfs("/", &s) >= 0 &&
172 return saved_in_initrd;
175 void in_initrd_force(bool value) {
176 saved_in_initrd = value;
179 #if 0 /// UNNEEDED by elogind
180 /* hey glibc, APIs with callbacks without a user pointer are so useless */
181 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
182 int (*compar) (const void *, const void *, void *), void *arg) {
191 p = (const char *) base + idx * size;
192 comparison = compar(key, p, arg);
195 else if (comparison > 0)
203 int on_ac_power(void) {
204 bool found_offline = false, found_online = false;
205 _cleanup_closedir_ DIR *d = NULL;
208 d = opendir("/sys/class/power_supply");
210 return errno == ENOENT ? true : -errno;
212 FOREACH_DIRENT(de, d, return -errno) {
213 _cleanup_close_ int fd = -1, device = -1;
217 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
219 if (IN_SET(errno, ENOENT, ENOTDIR))
225 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
233 n = read(fd, contents, sizeof(contents));
237 if (n != 6 || memcmp(contents, "Mains\n", 6))
241 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
249 n = read(fd, contents, sizeof(contents));
253 if (n != 2 || contents[1] != '\n')
256 if (contents[0] == '1') {
259 } else if (contents[0] == '0')
260 found_offline = true;
265 return found_online || !found_offline;
269 int container_get_leader(const char *machine, pid_t *pid) {
270 _cleanup_free_ char *s = NULL, *class = NULL;
278 if (!machine_name_is_valid(machine))
281 p = strjoina("/run/systemd/machines/", machine);
282 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
290 if (!streq_ptr(class, "container"))
293 r = parse_pid(s, &leader);
303 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
304 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
312 mntns = procfs_file_alloca(pid, "ns/mnt");
313 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
321 pidns = procfs_file_alloca(pid, "ns/pid");
322 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
330 netns = procfs_file_alloca(pid, "ns/net");
331 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
339 userns = procfs_file_alloca(pid, "ns/user");
340 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
341 if (usernsfd < 0 && errno != ENOENT)
348 root = procfs_file_alloca(pid, "root");
349 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
364 *userns_fd = usernsfd;
369 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
374 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
375 if (userns_fd >= 0) {
376 /* Can't setns to your own userns, since then you could
377 * escalate from non-root to root in your own namespace, so
378 * check if namespaces equal before attempting to enter. */
379 _cleanup_free_ char *userns_fd_path = NULL;
381 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
384 r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
392 if (setns(pidns_fd, CLONE_NEWPID) < 0)
396 if (setns(mntns_fd, CLONE_NEWNS) < 0)
400 if (setns(netns_fd, CLONE_NEWNET) < 0)
404 if (setns(userns_fd, CLONE_NEWUSER) < 0)
408 if (fchdir(root_fd) < 0)
415 return reset_uid_gid();
418 uint64_t physical_memory(void) {
419 _cleanup_free_ char *root = NULL, *value = NULL;
424 /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
427 * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
428 * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
430 sc = sysconf(_SC_PHYS_PAGES);
434 mem = (uint64_t) sc * (uint64_t) ps;
436 if (cg_get_root_path(&root) < 0)
439 if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value))
442 if (safe_atou64(value, &lim) < 0)
445 /* Make sure the limit is a multiple of our own page size */
449 return MIN(mem, lim);
452 uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
453 uint64_t p, m, ps, r;
457 /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
458 * the result is a multiple of the page size (rounds down). */
463 p = physical_memory() / ps;
479 uint64_t system_tasks_max(void) {
481 #if SIZEOF_PID_T == 4
482 #define TASKS_MAX ((uint64_t) (INT32_MAX-1))
483 #elif SIZEOF_PID_T == 2
484 #define TASKS_MAX ((uint64_t) (INT16_MAX-1))
486 #error "Unknown pid_t size"
489 _cleanup_free_ char *value = NULL, *root = NULL;
490 uint64_t a = TASKS_MAX, b = TASKS_MAX;
492 /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
495 * a) the maximum value for the pid_t type
496 * b) the cgroups pids_max attribute for the system
497 * c) the kernel's configure maximum PID value
499 * And then pick the smallest of the three */
501 if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0)
502 (void) safe_atou64(value, &a);
504 if (cg_get_root_path(&root) >= 0) {
505 value = mfree(value);
507 if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
508 (void) safe_atou64(value, &b);
511 return MIN3(TASKS_MAX,
512 a <= 0 ? TASKS_MAX : a,
513 b <= 0 ? TASKS_MAX : b);
516 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
521 /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
522 * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
524 t = system_tasks_max();
528 if (m / t != v) /* overflow? */
534 #if 0 /// UNNEEDED by elogind
535 int update_reboot_parameter_and_warn(const char *param) {
538 if (isempty(param)) {
539 if (unlink("/run/systemd/reboot-param") < 0) {
543 return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
549 RUN_WITH_UMASK(0022) {
550 r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
552 return log_warning_errno(r, "Failed to write reboot parameter file: %m");
560 puts(PACKAGE_STRING "\n"
565 #if 0 /// UNNEEDED by elogind