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"
67 char **saved_argv = NULL;
68 static int saved_in_initrd = -1;
70 size_t page_size(void) {
71 static thread_local size_t pgsz = 0;
74 if (_likely_(pgsz > 0))
77 r = sysconf(_SC_PAGESIZE);
84 #if 0 /// UNNEEDED by elogind
85 bool plymouth_running(void) {
86 return access("/run/plymouth/pid", F_OK) >= 0;
90 bool display_is_local(const char *display) {
99 int socket_from_display(const char *display, char **path) {
106 if (!display_is_local(display))
109 k = strspn(display+1, "0123456789");
111 f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1);
115 c = stpcpy(f, "/tmp/.X11-unix/X");
116 memcpy(c, display+1, k);
124 #if 0 /// UNNEEDED by elogind
125 bool kexec_loaded(void) {
126 _cleanup_free_ char *s = NULL;
128 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
134 int prot_from_flags(int flags) {
136 switch (flags & O_ACCMODE) {
145 return PROT_READ|PROT_WRITE;
153 bool in_initrd(void) {
156 if (saved_in_initrd >= 0)
157 return saved_in_initrd;
159 /* We make two checks here:
161 * 1. the flag file /etc/initrd-release must exist
162 * 2. the root file system must be a memory file system
164 * The second check is extra paranoia, since misdetecting an
165 * initrd can have bad consequences due the initrd
166 * emptying when transititioning to the main systemd.
169 saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
170 statfs("/", &s) >= 0 &&
173 return saved_in_initrd;
176 void in_initrd_force(bool value) {
177 saved_in_initrd = value;
180 #if 0 /// UNNEEDED by elogind
181 /* hey glibc, APIs with callbacks without a user pointer are so useless */
182 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
183 int (*compar) (const void *, const void *, void *), void *arg) {
192 p = (const char *) base + idx * size;
193 comparison = compar(key, p, arg);
196 else if (comparison > 0)
204 int on_ac_power(void) {
205 bool found_offline = false, found_online = false;
206 _cleanup_closedir_ DIR *d = NULL;
209 d = opendir("/sys/class/power_supply");
211 return errno == ENOENT ? true : -errno;
213 FOREACH_DIRENT(de, d, return -errno) {
214 _cleanup_close_ int fd = -1, device = -1;
218 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
220 if (IN_SET(errno, ENOENT, ENOTDIR))
226 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
234 n = read(fd, contents, sizeof(contents));
238 if (n != 6 || memcmp(contents, "Mains\n", 6))
242 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
250 n = read(fd, contents, sizeof(contents));
254 if (n != 2 || contents[1] != '\n')
257 if (contents[0] == '1') {
260 } else if (contents[0] == '0')
261 found_offline = true;
266 return found_online || !found_offline;
270 int container_get_leader(const char *machine, pid_t *pid) {
271 _cleanup_free_ char *s = NULL, *class = NULL;
279 if (!machine_name_is_valid(machine))
282 p = strjoina("/run/systemd/machines/", machine);
283 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
291 if (!streq_ptr(class, "container"))
294 r = parse_pid(s, &leader);
304 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
305 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
313 mntns = procfs_file_alloca(pid, "ns/mnt");
314 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
322 pidns = procfs_file_alloca(pid, "ns/pid");
323 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
331 netns = procfs_file_alloca(pid, "ns/net");
332 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
340 userns = procfs_file_alloca(pid, "ns/user");
341 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
342 if (usernsfd < 0 && errno != ENOENT)
349 root = procfs_file_alloca(pid, "root");
350 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
365 *userns_fd = usernsfd;
370 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
375 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
376 if (userns_fd >= 0) {
377 /* Can't setns to your own userns, since then you could
378 * escalate from non-root to root in your own namespace, so
379 * check if namespaces equal before attempting to enter. */
380 _cleanup_free_ char *userns_fd_path = NULL;
382 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
385 r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
393 if (setns(pidns_fd, CLONE_NEWPID) < 0)
397 if (setns(mntns_fd, CLONE_NEWNS) < 0)
401 if (setns(netns_fd, CLONE_NEWNET) < 0)
405 if (setns(userns_fd, CLONE_NEWUSER) < 0)
409 if (fchdir(root_fd) < 0)
416 return reset_uid_gid();
419 uint64_t physical_memory(void) {
420 _cleanup_free_ char *root = NULL, *value = NULL;
425 /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
428 * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
429 * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
431 sc = sysconf(_SC_PHYS_PAGES);
435 mem = (uint64_t) sc * (uint64_t) ps;
437 if (cg_get_root_path(&root) < 0)
440 if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value))
443 if (safe_atou64(value, &lim) < 0)
446 /* Make sure the limit is a multiple of our own page size */
450 return MIN(mem, lim);
453 uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
454 uint64_t p, m, ps, r;
458 /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
459 * the result is a multiple of the page size (rounds down). */
464 p = physical_memory() / ps;
480 uint64_t system_tasks_max(void) {
482 #if SIZEOF_PID_T == 4
483 #define TASKS_MAX ((uint64_t) (INT32_MAX-1))
484 #elif SIZEOF_PID_T == 2
485 #define TASKS_MAX ((uint64_t) (INT16_MAX-1))
487 #error "Unknown pid_t size"
490 _cleanup_free_ char *value = NULL, *root = NULL;
491 uint64_t a = TASKS_MAX, b = TASKS_MAX;
493 /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
496 * a) the maximum value for the pid_t type
497 * b) the cgroups pids_max attribute for the system
498 * c) the kernel's configure maximum PID value
500 * And then pick the smallest of the three */
502 if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0)
503 (void) safe_atou64(value, &a);
505 if (cg_get_root_path(&root) >= 0) {
506 value = mfree(value);
508 if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
509 (void) safe_atou64(value, &b);
512 return MIN3(TASKS_MAX,
513 a <= 0 ? TASKS_MAX : a,
514 b <= 0 ? TASKS_MAX : b);
517 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
522 /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
523 * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
525 t = system_tasks_max();
529 if (m / t != v) /* overflow? */
535 #if 0 /// UNNEEDED by elogind
536 int update_reboot_parameter_and_warn(const char *param) {
539 if (isempty(param)) {
540 if (unlink("/run/systemd/reboot-param") < 0) {
544 return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
550 RUN_WITH_UMASK(0022) {
551 r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
553 return log_warning_errno(r, "Failed to write reboot parameter file: %m");
561 puts(PACKAGE_STRING "\n"
566 #if 0 /// UNNEEDED by elogind
568 /* This is a direct translation of str_verscmp from boot.c */
569 static bool is_digit(int c) {
570 return c >= '0' && c <= '9';
573 static int c_order(int c) {
574 if (c == 0 || is_digit(c))
577 if ((c >= 'a') && (c <= 'z'))
583 int str_verscmp(const char *s1, const char *s2) {
584 const char *os1, *os2;
595 while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
598 order = c_order(*s1) - c_order(*s2);
611 while (is_digit(*s1) && is_digit(*s2)) {
627 return strcmp(os1, os2);
630 /* Turn off core dumps but only if we're running outside of a container. */
631 void disable_core_dumps(void) {
632 if (detect_container() <= 0)
633 (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);