]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/util.c
2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include <sys/prctl.h>
31 #include <sys/statfs.h>
32 #include <sys/sysmacros.h>
33 #include <sys/types.h>
36 #include "alloc-util.h"
38 #include "cgroup-util.h"
40 #include "dirent-util.h"
43 #include "format-util.h"
45 #include "hostname-util.h"
49 #include "parse-util.h"
50 #include "path-util.h"
51 #include "process-util.h"
53 #include "signal-util.h"
54 #include "stat-util.h"
55 #include "string-util.h"
57 #include "time-util.h"
58 #include "umask-util.h"
59 #include "user-util.h"
63 char **saved_argv
= NULL
;
64 static int saved_in_initrd
= -1;
66 size_t page_size(void) {
67 static thread_local
size_t pgsz
= 0;
70 if (_likely_(pgsz
> 0))
73 r
= sysconf(_SC_PAGESIZE
);
80 bool plymouth_running(void) {
81 return access("/run/plymouth/pid", F_OK
) >= 0;
84 bool display_is_local(const char *display
) {
93 int socket_from_display(const char *display
, char **path
) {
100 if (!display_is_local(display
))
103 k
= strspn(display
+1, "0123456789");
105 f
= new(char, strlen("/tmp/.X11-unix/X") + k
+ 1);
109 c
= stpcpy(f
, "/tmp/.X11-unix/X");
110 memcpy(c
, display
+1, k
);
118 int block_get_whole_disk(dev_t d
, dev_t
*ret
) {
125 /* If it has a queue this is good enough for us */
126 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", major(d
), minor(d
)) < 0)
137 /* If it is a partition find the originating device */
138 if (asprintf(&p
, "/sys/dev/block/%u:%u/partition", major(d
), minor(d
)) < 0)
147 /* Get parent dev_t */
148 if (asprintf(&p
, "/sys/dev/block/%u:%u/../dev", major(d
), minor(d
)) < 0)
151 r
= read_one_line_file(p
, &s
);
157 r
= sscanf(s
, "%u:%u", &m
, &n
);
163 /* Only return this if it is really good enough for us. */
164 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", m
, n
) < 0)
171 *ret
= makedev(m
, n
);
178 bool kexec_loaded(void) {
182 if (read_one_line_file("/sys/kernel/kexec_loaded", &s
) >= 0) {
190 int prot_from_flags(int flags
) {
192 switch (flags
& O_ACCMODE
) {
201 return PROT_READ
|PROT_WRITE
;
208 int fork_agent(pid_t
*pid
, const int except
[], unsigned n_except
, const char *path
, ...) {
209 bool stdout_is_tty
, stderr_is_tty
;
210 pid_t parent_pid
, agent_pid
;
211 sigset_t ss
, saved_ss
;
219 /* Spawns a temporary TTY agent, making sure it goes away when
222 parent_pid
= getpid();
224 /* First we temporarily block all signals, so that the new
225 * child has them blocked initially. This way, we can be sure
226 * that SIGTERMs are not lost we might send to the agent. */
227 assert_se(sigfillset(&ss
) >= 0);
228 assert_se(sigprocmask(SIG_SETMASK
, &ss
, &saved_ss
) >= 0);
232 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
236 if (agent_pid
!= 0) {
237 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
244 * Make sure the agent goes away when the parent dies */
245 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
248 /* Make sure we actually can kill the agent, if we need to, in
249 * case somebody invoked us from a shell script that trapped
250 * SIGTERM or so... */
251 (void) reset_all_signal_handlers();
252 (void) reset_signal_mask();
254 /* Check whether our parent died before we were able
255 * to set the death signal and unblock the signals */
256 if (getppid() != parent_pid
)
259 /* Don't leak fds to the agent */
260 close_all_fds(except
, n_except
);
262 stdout_is_tty
= isatty(STDOUT_FILENO
);
263 stderr_is_tty
= isatty(STDERR_FILENO
);
265 if (!stdout_is_tty
|| !stderr_is_tty
) {
268 /* Detach from stdout/stderr. and reopen
269 * /dev/tty for them. This is important to
270 * ensure that when systemctl is started via
271 * popen() or a similar call that expects to
272 * read EOF we actually do generate EOF and
273 * not delay this indefinitely by because we
274 * keep an unused copy of stdin around. */
275 fd
= open("/dev/tty", O_WRONLY
);
277 log_error_errno(errno
, "Failed to open /dev/tty: %m");
281 if (!stdout_is_tty
&& dup2(fd
, STDOUT_FILENO
) < 0) {
282 log_error_errno(errno
, "Failed to dup2 /dev/tty: %m");
286 if (!stderr_is_tty
&& dup2(fd
, STDERR_FILENO
) < 0) {
287 log_error_errno(errno
, "Failed to dup2 /dev/tty: %m");
291 if (fd
> STDERR_FILENO
)
295 /* Count arguments */
297 for (n
= 0; va_arg(ap
, char*); n
++)
302 l
= alloca(sizeof(char *) * (n
+ 1));
304 /* Fill in arguments */
306 for (i
= 0; i
<= n
; i
++)
307 l
[i
] = va_arg(ap
, char*);
314 bool in_initrd(void) {
317 if (saved_in_initrd
>= 0)
318 return saved_in_initrd
;
320 /* We make two checks here:
322 * 1. the flag file /etc/initrd-release must exist
323 * 2. the root file system must be a memory file system
325 * The second check is extra paranoia, since misdetecting an
326 * initrd can have bad consequences due the initrd
327 * emptying when transititioning to the main systemd.
330 saved_in_initrd
= access("/etc/initrd-release", F_OK
) >= 0 &&
331 statfs("/", &s
) >= 0 &&
334 return saved_in_initrd
;
337 void in_initrd_force(bool value
) {
338 saved_in_initrd
= value
;
341 /* hey glibc, APIs with callbacks without a user pointer are so useless */
342 void *xbsearch_r(const void *key
, const void *base
, size_t nmemb
, size_t size
,
343 int (*compar
) (const void *, const void *, void *), void *arg
) {
352 p
= (const char *) base
+ idx
* size
;
353 comparison
= compar(key
, p
, arg
);
356 else if (comparison
> 0)
364 int on_ac_power(void) {
365 bool found_offline
= false, found_online
= false;
366 _cleanup_closedir_
DIR *d
= NULL
;
369 d
= opendir("/sys/class/power_supply");
371 return errno
== ENOENT
? true : -errno
;
373 FOREACH_DIRENT(de
, d
, return -errno
) {
374 _cleanup_close_
int fd
= -1, device
= -1;
378 device
= openat(dirfd(d
), de
->d_name
, O_DIRECTORY
|O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
380 if (errno
== ENOENT
|| errno
== ENOTDIR
)
386 fd
= openat(device
, "type", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
394 n
= read(fd
, contents
, sizeof(contents
));
398 if (n
!= 6 || memcmp(contents
, "Mains\n", 6))
402 fd
= openat(device
, "online", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
410 n
= read(fd
, contents
, sizeof(contents
));
414 if (n
!= 2 || contents
[1] != '\n')
417 if (contents
[0] == '1') {
420 } else if (contents
[0] == '0')
421 found_offline
= true;
426 return found_online
|| !found_offline
;
429 int container_get_leader(const char *machine
, pid_t
*pid
) {
430 _cleanup_free_
char *s
= NULL
, *class = NULL
;
438 if (!machine_name_is_valid(machine
))
441 p
= strjoina("/run/systemd/machines/", machine
);
442 r
= parse_env_file(p
, NEWLINE
, "LEADER", &s
, "CLASS", &class, NULL
);
450 if (!streq_ptr(class, "container"))
453 r
= parse_pid(s
, &leader
);
463 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
464 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
472 mntns
= procfs_file_alloca(pid
, "ns/mnt");
473 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
481 pidns
= procfs_file_alloca(pid
, "ns/pid");
482 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
490 netns
= procfs_file_alloca(pid
, "ns/net");
491 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
499 userns
= procfs_file_alloca(pid
, "ns/user");
500 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
501 if (usernsfd
< 0 && errno
!= ENOENT
)
508 root
= procfs_file_alloca(pid
, "root");
509 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
524 *userns_fd
= usernsfd
;
529 pidnsfd
= mntnsfd
= netnsfd
= usernsfd
= -1;
534 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
535 if (userns_fd
>= 0) {
536 /* Can't setns to your own userns, since then you could
537 * escalate from non-root to root in your own namespace, so
538 * check if namespaces equal before attempting to enter. */
539 _cleanup_free_
char *userns_fd_path
= NULL
;
541 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
544 r
= files_same(userns_fd_path
, "/proc/self/ns/user", 0);
552 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
556 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
560 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
564 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
568 if (fchdir(root_fd
) < 0)
575 return reset_uid_gid();
578 uint64_t physical_memory(void) {
579 _cleanup_free_
char *root
= NULL
, *value
= NULL
;
584 /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
587 * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
588 * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
590 sc
= sysconf(_SC_PHYS_PAGES
);
594 mem
= (uint64_t) sc
* (uint64_t) ps
;
596 if (cg_get_root_path(&root
) < 0)
599 if (cg_get_attribute("memory", root
, "memory.limit_in_bytes", &value
))
602 if (safe_atou64(value
, &lim
) < 0)
605 /* Make sure the limit is a multiple of our own page size */
609 return MIN(mem
, lim
);
612 uint64_t physical_memory_scale(uint64_t v
, uint64_t max
) {
613 uint64_t p
, m
, ps
, r
;
617 /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
618 * the result is a multiple of the page size (rounds down). */
623 p
= physical_memory() / ps
;
639 uint64_t system_tasks_max(void) {
641 #if SIZEOF_PID_T == 4
642 #define TASKS_MAX ((uint64_t) (INT32_MAX-1))
643 #elif SIZEOF_PID_T == 2
644 #define TASKS_MAX ((uint64_t) (INT16_MAX-1))
646 #error "Unknown pid_t size"
649 _cleanup_free_
char *value
= NULL
, *root
= NULL
;
650 uint64_t a
= TASKS_MAX
, b
= TASKS_MAX
;
652 /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
655 * a) the maximum value for the pid_t type
656 * b) the cgroups pids_max attribute for the system
657 * c) the kernel's configure maximum PID value
659 * And then pick the smallest of the three */
661 if (read_one_line_file("/proc/sys/kernel/pid_max", &value
) >= 0)
662 (void) safe_atou64(value
, &a
);
664 if (cg_get_root_path(&root
) >= 0) {
665 value
= mfree(value
);
667 if (cg_get_attribute("pids", root
, "pids.max", &value
) >= 0)
668 (void) safe_atou64(value
, &b
);
671 return MIN3(TASKS_MAX
,
672 a
<= 0 ? TASKS_MAX
: a
,
673 b
<= 0 ? TASKS_MAX
: b
);
676 uint64_t system_tasks_max_scale(uint64_t v
, uint64_t max
) {
681 /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
682 * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
684 t
= system_tasks_max();
688 if (m
/ t
!= v
) /* overflow? */
694 int update_reboot_parameter_and_warn(const char *param
) {
697 if (isempty(param
)) {
698 if (unlink("/run/systemd/reboot-param") < 0) {
702 return log_warning_errno(errno
, "Failed to unlink reboot parameter file: %m");
708 RUN_WITH_UMASK(0022) {
709 r
= write_string_file("/run/systemd/reboot-param", param
, WRITE_STRING_FILE_CREATE
);
711 return log_warning_errno(r
, "Failed to write reboot parameter file: %m");
718 puts(PACKAGE_STRING
"\n"