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/>.
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"
40 #include "dirent-util.h"
43 #include "formats-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 "user-util.h"
61 /* Put this test here for a lack of better place */
62 assert_cc(EAGAIN
== EWOULDBLOCK
);
65 char **saved_argv
= NULL
;
67 size_t page_size(void) {
68 static thread_local
size_t pgsz
= 0;
71 if (_likely_(pgsz
> 0))
74 r
= sysconf(_SC_PAGESIZE
);
81 static int do_execute(char **directories
, usec_t timeout
, char *argv
[]) {
82 _cleanup_hashmap_free_free_ Hashmap
*pids
= NULL
;
83 _cleanup_set_free_free_ Set
*seen
= NULL
;
86 /* We fork this all off from a child process so that we can
87 * somewhat cleanly make use of SIGALRM to set a time limit */
89 (void) reset_all_signal_handlers();
90 (void) reset_signal_mask();
92 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
94 pids
= hashmap_new(NULL
);
98 seen
= set_new(&string_hash_ops
);
102 STRV_FOREACH(directory
, directories
) {
103 _cleanup_closedir_
DIR *d
;
106 d
= opendir(*directory
);
111 return log_error_errno(errno
, "Failed to open directory %s: %m", *directory
);
114 FOREACH_DIRENT(de
, d
, break) {
115 _cleanup_free_
char *path
= NULL
;
119 if (!dirent_is_file(de
))
122 if (set_contains(seen
, de
->d_name
)) {
123 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory
, de
->d_name
);
127 r
= set_put_strdup(seen
, de
->d_name
);
131 path
= strjoin(*directory
, "/", de
->d_name
, NULL
);
135 if (null_or_empty_path(path
)) {
136 log_debug("%s is empty (a mask).", path
);
142 log_error_errno(errno
, "Failed to fork: %m");
144 } else if (pid
== 0) {
147 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
157 return log_error_errno(errno
, "Failed to execute %s: %m", path
);
160 log_debug("Spawned %s as " PID_FMT
".", path
, pid
);
162 r
= hashmap_put(pids
, PID_TO_PTR(pid
), path
);
169 /* Abort execution of this process after the timout. We simply
170 * rely on SIGALRM as default action terminating the process,
171 * and turn on alarm(). */
173 if (timeout
!= USEC_INFINITY
)
174 alarm((timeout
+ USEC_PER_SEC
- 1) / USEC_PER_SEC
);
176 while (!hashmap_isempty(pids
)) {
177 _cleanup_free_
char *path
= NULL
;
180 pid
= PTR_TO_PID(hashmap_first_key(pids
));
183 path
= hashmap_remove(pids
, PID_TO_PTR(pid
));
186 wait_for_terminate_and_warn(path
, pid
, true);
192 void execute_directories(const char* const* directories
, usec_t timeout
, char *argv
[]) {
196 char **dirs
= (char**) directories
;
198 assert(!strv_isempty(dirs
));
200 name
= basename(dirs
[0]);
201 assert(!isempty(name
));
203 /* Executes all binaries in the directories in parallel and waits
204 * for them to finish. Optionally a timeout is applied. If a file
205 * with the same name exists in more than one directory, the
206 * earliest one wins. */
208 executor_pid
= fork();
209 if (executor_pid
< 0) {
210 log_error_errno(errno
, "Failed to fork: %m");
213 } else if (executor_pid
== 0) {
214 r
= do_execute(dirs
, timeout
, argv
);
215 _exit(r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
218 wait_for_terminate_and_warn(name
, executor_pid
, true);
221 bool plymouth_running(void) {
222 return access("/run/plymouth/pid", F_OK
) >= 0;
225 bool display_is_local(const char *display
) {
234 int socket_from_display(const char *display
, char **path
) {
241 if (!display_is_local(display
))
244 k
= strspn(display
+1, "0123456789");
246 f
= new(char, strlen("/tmp/.X11-unix/X") + k
+ 1);
250 c
= stpcpy(f
, "/tmp/.X11-unix/X");
251 memcpy(c
, display
+1, k
);
259 int block_get_whole_disk(dev_t d
, dev_t
*ret
) {
266 /* If it has a queue this is good enough for us */
267 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", major(d
), minor(d
)) < 0)
278 /* If it is a partition find the originating device */
279 if (asprintf(&p
, "/sys/dev/block/%u:%u/partition", major(d
), minor(d
)) < 0)
288 /* Get parent dev_t */
289 if (asprintf(&p
, "/sys/dev/block/%u:%u/../dev", major(d
), minor(d
)) < 0)
292 r
= read_one_line_file(p
, &s
);
298 r
= sscanf(s
, "%u:%u", &m
, &n
);
304 /* Only return this if it is really good enough for us. */
305 if (asprintf(&p
, "/sys/dev/block/%u:%u/queue", m
, n
) < 0)
312 *ret
= makedev(m
, n
);
319 bool kexec_loaded(void) {
323 if (read_one_line_file("/sys/kernel/kexec_loaded", &s
) >= 0) {
331 int prot_from_flags(int flags
) {
333 switch (flags
& O_ACCMODE
) {
342 return PROT_READ
|PROT_WRITE
;
349 int fork_agent(pid_t
*pid
, const int except
[], unsigned n_except
, const char *path
, ...) {
350 bool stdout_is_tty
, stderr_is_tty
;
351 pid_t parent_pid
, agent_pid
;
352 sigset_t ss
, saved_ss
;
360 /* Spawns a temporary TTY agent, making sure it goes away when
363 parent_pid
= getpid();
365 /* First we temporarily block all signals, so that the new
366 * child has them blocked initially. This way, we can be sure
367 * that SIGTERMs are not lost we might send to the agent. */
368 assert_se(sigfillset(&ss
) >= 0);
369 assert_se(sigprocmask(SIG_SETMASK
, &ss
, &saved_ss
) >= 0);
373 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
377 if (agent_pid
!= 0) {
378 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
385 * Make sure the agent goes away when the parent dies */
386 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
389 /* Make sure we actually can kill the agent, if we need to, in
390 * case somebody invoked us from a shell script that trapped
391 * SIGTERM or so... */
392 (void) reset_all_signal_handlers();
393 (void) reset_signal_mask();
395 /* Check whether our parent died before we were able
396 * to set the death signal and unblock the signals */
397 if (getppid() != parent_pid
)
400 /* Don't leak fds to the agent */
401 close_all_fds(except
, n_except
);
403 stdout_is_tty
= isatty(STDOUT_FILENO
);
404 stderr_is_tty
= isatty(STDERR_FILENO
);
406 if (!stdout_is_tty
|| !stderr_is_tty
) {
409 /* Detach from stdout/stderr. and reopen
410 * /dev/tty for them. This is important to
411 * ensure that when systemctl is started via
412 * popen() or a similar call that expects to
413 * read EOF we actually do generate EOF and
414 * not delay this indefinitely by because we
415 * keep an unused copy of stdin around. */
416 fd
= open("/dev/tty", O_WRONLY
);
418 log_error_errno(errno
, "Failed to open /dev/tty: %m");
423 dup2(fd
, STDOUT_FILENO
);
426 dup2(fd
, STDERR_FILENO
);
432 /* Count arguments */
434 for (n
= 0; va_arg(ap
, char*); n
++)
439 l
= alloca(sizeof(char *) * (n
+ 1));
441 /* Fill in arguments */
443 for (i
= 0; i
<= n
; i
++)
444 l
[i
] = va_arg(ap
, char*);
451 bool in_initrd(void) {
452 static int saved
= -1;
458 /* We make two checks here:
460 * 1. the flag file /etc/initrd-release must exist
461 * 2. the root file system must be a memory file system
463 * The second check is extra paranoia, since misdetecting an
464 * initrd can have bad bad consequences due the initrd
465 * emptying when transititioning to the main systemd.
468 saved
= access("/etc/initrd-release", F_OK
) >= 0 &&
469 statfs("/", &s
) >= 0 &&
475 /* hey glibc, APIs with callbacks without a user pointer are so useless */
476 void *xbsearch_r(const void *key
, const void *base
, size_t nmemb
, size_t size
,
477 int (*compar
) (const void *, const void *, void *), void *arg
) {
486 p
= (void *)(((const char *) base
) + (idx
* size
));
487 comparison
= compar(key
, p
, arg
);
490 else if (comparison
> 0)
498 int on_ac_power(void) {
499 bool found_offline
= false, found_online
= false;
500 _cleanup_closedir_
DIR *d
= NULL
;
502 d
= opendir("/sys/class/power_supply");
504 return errno
== ENOENT
? true : -errno
;
508 _cleanup_close_
int fd
= -1, device
= -1;
514 if (!de
&& errno
> 0)
520 if (hidden_file(de
->d_name
))
523 device
= openat(dirfd(d
), de
->d_name
, O_DIRECTORY
|O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
525 if (errno
== ENOENT
|| errno
== ENOTDIR
)
531 fd
= openat(device
, "type", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
539 n
= read(fd
, contents
, sizeof(contents
));
543 if (n
!= 6 || memcmp(contents
, "Mains\n", 6))
547 fd
= openat(device
, "online", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
555 n
= read(fd
, contents
, sizeof(contents
));
559 if (n
!= 2 || contents
[1] != '\n')
562 if (contents
[0] == '1') {
565 } else if (contents
[0] == '0')
566 found_offline
= true;
571 return found_online
|| !found_offline
;
574 bool id128_is_valid(const char *s
) {
580 /* Simple formatted 128bit hex string */
582 for (i
= 0; i
< l
; i
++) {
585 if (!(c
>= '0' && c
<= '9') &&
586 !(c
>= 'a' && c
<= 'z') &&
587 !(c
>= 'A' && c
<= 'Z'))
591 } else if (l
== 36) {
595 for (i
= 0; i
< l
; i
++) {
598 if ((i
== 8 || i
== 13 || i
== 18 || i
== 23)) {
602 if (!(c
>= '0' && c
<= '9') &&
603 !(c
>= 'a' && c
<= 'z') &&
604 !(c
>= 'A' && c
<= 'Z'))
615 int container_get_leader(const char *machine
, pid_t
*pid
) {
616 _cleanup_free_
char *s
= NULL
, *class = NULL
;
624 if (!machine_name_is_valid(machine
))
627 p
= strjoina("/run/systemd/machines/", machine
);
628 r
= parse_env_file(p
, NEWLINE
, "LEADER", &s
, "CLASS", &class, NULL
);
636 if (!streq_ptr(class, "container"))
639 r
= parse_pid(s
, &leader
);
649 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
650 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
658 mntns
= procfs_file_alloca(pid
, "ns/mnt");
659 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
667 pidns
= procfs_file_alloca(pid
, "ns/pid");
668 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
676 netns
= procfs_file_alloca(pid
, "ns/net");
677 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
685 userns
= procfs_file_alloca(pid
, "ns/user");
686 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
687 if (usernsfd
< 0 && errno
!= ENOENT
)
694 root
= procfs_file_alloca(pid
, "root");
695 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
710 *userns_fd
= usernsfd
;
715 pidnsfd
= mntnsfd
= netnsfd
= usernsfd
= -1;
720 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
721 if (userns_fd
>= 0) {
722 /* Can't setns to your own userns, since then you could
723 * escalate from non-root to root in your own namespace, so
724 * check if namespaces equal before attempting to enter. */
725 _cleanup_free_
char *userns_fd_path
= NULL
;
727 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
730 r
= files_same(userns_fd_path
, "/proc/self/ns/user");
738 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
742 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
746 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
750 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
754 if (fchdir(root_fd
) < 0)
761 return reset_uid_gid();
764 uint64_t physical_memory(void) {
767 /* We return this as uint64_t in case we are running as 32bit
768 * process on a 64bit kernel with huge amounts of memory */
770 mem
= sysconf(_SC_PHYS_PAGES
);
773 return (uint64_t) mem
* (uint64_t) page_size();
776 int update_reboot_param_file(const char *param
) {
780 r
= write_string_file(REBOOT_PARAM_FILE
, param
, WRITE_STRING_FILE_CREATE
);
782 return log_error_errno(r
, "Failed to write reboot param to "REBOOT_PARAM_FILE
": %m");
784 (void) unlink(REBOOT_PARAM_FILE
);
790 puts(PACKAGE_STRING
"\n"