1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 //#include <langinfo.h>
28 //#include <libintl.h>
30 //#include <linux/magic.h>
31 //#include <linux/oom.h>
32 //#include <linux/sched.h>
42 //#include <sys/file.h>
43 //#include <sys/ioctl.h>
44 //#include <sys/mman.h>
45 //#include <sys/mount.h>
46 //#include <sys/personality.h>
47 #include <sys/prctl.h>
48 //#include <sys/stat.h>
49 //#include <sys/statvfs.h>
50 //#include <sys/time.h>
51 //#include <sys/types.h>
52 //#include <sys/utsname.h>
53 //#include <sys/vfs.h>
54 //#include <sys/wait.h>
58 /* When we include libgen.h because we need dirname() we immediately
59 * undefine basename() since libgen.h defines it as a macro to the
60 * POSIX version which is really broken. We prefer GNU basename(). */
64 #ifdef HAVE_SYS_AUXV_H
68 /* We include linux/fs.h as last of the system headers, as it
69 * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
70 //#include <linux/fs.h>
72 #include "alloc-util.h"
75 //#include "device-nodes.h"
76 #include "dirent-util.h"
77 //#include "env-util.h"
79 //#include "exit-status.h"
82 //#include "formats-util.h"
83 //#include "gunicode.h"
85 //#include "hexdecoct.h"
86 #include "hostname-util.h"
90 //#include "missing.h"
92 #include "parse-util.h"
93 //#include "path-util.h"
94 #include "process-util.h"
95 //#include "random-util.h"
96 #include "signal-util.h"
98 //#include "sparse-endian.h"
99 #include "stat-util.h"
100 //#include "string-table.h"
101 #include "string-util.h"
103 //#include "terminal-util.h"
104 #include "user-util.h"
109 /* Put this test here for a lack of better place */
110 assert_cc(EAGAIN == EWOULDBLOCK);
113 char **saved_argv = NULL;
115 size_t page_size(void) {
116 static thread_local size_t pgsz = 0;
119 if (_likely_(pgsz > 0))
122 r = sysconf(_SC_PAGESIZE);
129 static int do_execute(char **directories, usec_t timeout, char *argv[]) {
130 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
131 _cleanup_set_free_free_ Set *seen = NULL;
134 /* We fork this all off from a child process so that we can
135 * somewhat cleanly make use of SIGALRM to set a time limit */
137 (void) reset_all_signal_handlers();
138 (void) reset_signal_mask();
140 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
142 pids = hashmap_new(NULL);
146 seen = set_new(&string_hash_ops);
150 STRV_FOREACH(directory, directories) {
151 _cleanup_closedir_ DIR *d;
154 d = opendir(*directory);
159 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
162 FOREACH_DIRENT(de, d, break) {
163 _cleanup_free_ char *path = NULL;
167 if (!dirent_is_file(de))
170 if (set_contains(seen, de->d_name)) {
171 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
175 r = set_put_strdup(seen, de->d_name);
179 path = strjoin(*directory, "/", de->d_name, NULL);
183 if (null_or_empty_path(path)) {
184 log_debug("%s is empty (a mask).", path);
190 log_error_errno(errno, "Failed to fork: %m");
192 } else if (pid == 0) {
195 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
205 return log_error_errno(errno, "Failed to execute %s: %m", path);
208 log_debug("Spawned %s as " PID_FMT ".", path, pid);
210 r = hashmap_put(pids, PID_TO_PTR(pid), path);
217 /* Abort execution of this process after the timout. We simply
218 * rely on SIGALRM as default action terminating the process,
219 * and turn on alarm(). */
221 if (timeout != USEC_INFINITY)
222 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
224 while (!hashmap_isempty(pids)) {
225 _cleanup_free_ char *path = NULL;
228 pid = PTR_TO_PID(hashmap_first_key(pids));
231 path = hashmap_remove(pids, PID_TO_PTR(pid));
234 wait_for_terminate_and_warn(path, pid, true);
240 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
244 char **dirs = (char**) directories;
246 assert(!strv_isempty(dirs));
248 name = basename(dirs[0]);
249 assert(!isempty(name));
251 /* Executes all binaries in the directories in parallel and waits
252 * for them to finish. Optionally a timeout is applied. If a file
253 * with the same name exists in more than one directory, the
254 * earliest one wins. */
256 executor_pid = fork();
257 if (executor_pid < 0) {
258 log_error_errno(errno, "Failed to fork: %m");
261 } else if (executor_pid == 0) {
262 r = do_execute(dirs, timeout, argv);
263 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
266 wait_for_terminate_and_warn(name, executor_pid, true);
269 #if 0 /// UNNEEDED by elogind
270 bool plymouth_running(void) {
271 return access("/run/plymouth/pid", F_OK) >= 0;
275 bool display_is_local(const char *display) {
284 int socket_from_display(const char *display, char **path) {
291 if (!display_is_local(display))
294 k = strspn(display+1, "0123456789");
296 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
300 c = stpcpy(f, "/tmp/.X11-unix/X");
301 memcpy(c, display+1, k);
309 #if 0 /// UNNEEDED by elogind
310 int block_get_whole_disk(dev_t d, dev_t *ret) {
317 /* If it has a queue this is good enough for us */
318 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
329 /* If it is a partition find the originating device */
330 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
339 /* Get parent dev_t */
340 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
343 r = read_one_line_file(p, &s);
349 r = sscanf(s, "%u:%u", &m, &n);
355 /* Only return this if it is really good enough for us. */
356 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
363 *ret = makedev(m, n);
370 bool kexec_loaded(void) {
374 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
382 int prot_from_flags(int flags) {
384 switch (flags & O_ACCMODE) {
393 return PROT_READ|PROT_WRITE;
401 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
402 bool stdout_is_tty, stderr_is_tty;
403 pid_t parent_pid, agent_pid;
404 sigset_t ss, saved_ss;
412 /* Spawns a temporary TTY agent, making sure it goes away when
415 parent_pid = getpid();
417 /* First we temporarily block all signals, so that the new
418 * child has them blocked initially. This way, we can be sure
419 * that SIGTERMs are not lost we might send to the agent. */
420 assert_se(sigfillset(&ss) >= 0);
421 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
425 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
429 if (agent_pid != 0) {
430 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
437 * Make sure the agent goes away when the parent dies */
438 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
441 /* Make sure we actually can kill the agent, if we need to, in
442 * case somebody invoked us from a shell script that trapped
443 * SIGTERM or so... */
444 (void) reset_all_signal_handlers();
445 (void) reset_signal_mask();
447 /* Check whether our parent died before we were able
448 * to set the death signal and unblock the signals */
449 if (getppid() != parent_pid)
452 /* Don't leak fds to the agent */
453 close_all_fds(except, n_except);
455 stdout_is_tty = isatty(STDOUT_FILENO);
456 stderr_is_tty = isatty(STDERR_FILENO);
458 if (!stdout_is_tty || !stderr_is_tty) {
461 /* Detach from stdout/stderr. and reopen
462 * /dev/tty for them. This is important to
463 * ensure that when systemctl is started via
464 * popen() or a similar call that expects to
465 * read EOF we actually do generate EOF and
466 * not delay this indefinitely by because we
467 * keep an unused copy of stdin around. */
468 fd = open("/dev/tty", O_WRONLY);
470 log_error_errno(errno, "Failed to open /dev/tty: %m");
475 dup2(fd, STDOUT_FILENO);
478 dup2(fd, STDERR_FILENO);
484 /* Count arguments */
486 for (n = 0; va_arg(ap, char*); n++)
491 l = alloca(sizeof(char *) * (n + 1));
493 /* Fill in arguments */
495 for (i = 0; i <= n; i++)
496 l[i] = va_arg(ap, char*);
503 bool in_initrd(void) {
504 static int saved = -1;
510 /* We make two checks here:
512 * 1. the flag file /etc/initrd-release must exist
513 * 2. the root file system must be a memory file system
515 * The second check is extra paranoia, since misdetecting an
516 * initrd can have bad bad consequences due the initrd
517 * emptying when transititioning to the main systemd.
520 saved = access("/etc/initrd-release", F_OK) >= 0 &&
521 statfs("/", &s) >= 0 &&
527 #if 0 /// UNNEEDED by elogind
528 /* hey glibc, APIs with callbacks without a user pointer are so useless */
529 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
530 int (*compar) (const void *, const void *, void *), void *arg) {
539 p = (void *)(((const char *) base) + (idx * size));
540 comparison = compar(key, p, arg);
543 else if (comparison > 0)
551 int on_ac_power(void) {
552 bool found_offline = false, found_online = false;
553 _cleanup_closedir_ DIR *d = NULL;
555 d = opendir("/sys/class/power_supply");
557 return errno == ENOENT ? true : -errno;
561 _cleanup_close_ int fd = -1, device = -1;
567 if (!de && errno > 0)
573 if (hidden_file(de->d_name))
576 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
578 if (errno == ENOENT || errno == ENOTDIR)
584 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
592 n = read(fd, contents, sizeof(contents));
596 if (n != 6 || memcmp(contents, "Mains\n", 6))
600 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
608 n = read(fd, contents, sizeof(contents));
612 if (n != 2 || contents[1] != '\n')
615 if (contents[0] == '1') {
618 } else if (contents[0] == '0')
619 found_offline = true;
624 return found_online || !found_offline;
627 bool id128_is_valid(const char *s) {
633 /* Simple formatted 128bit hex string */
635 for (i = 0; i < l; i++) {
638 if (!(c >= '0' && c <= '9') &&
639 !(c >= 'a' && c <= 'z') &&
640 !(c >= 'A' && c <= 'Z'))
644 } else if (l == 36) {
648 for (i = 0; i < l; i++) {
651 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
655 if (!(c >= '0' && c <= '9') &&
656 !(c >= 'a' && c <= 'z') &&
657 !(c >= 'A' && c <= 'Z'))
669 int container_get_leader(const char *machine, pid_t *pid) {
670 _cleanup_free_ char *s = NULL, *class = NULL;
678 if (!machine_name_is_valid(machine))
681 p = strjoina("/run/systemd/machines/", machine);
682 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
690 if (!streq_ptr(class, "container"))
693 r = parse_pid(s, &leader);
703 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
704 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
712 mntns = procfs_file_alloca(pid, "ns/mnt");
713 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
721 pidns = procfs_file_alloca(pid, "ns/pid");
722 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
730 netns = procfs_file_alloca(pid, "ns/net");
731 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
739 userns = procfs_file_alloca(pid, "ns/user");
740 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
741 if (usernsfd < 0 && errno != ENOENT)
748 root = procfs_file_alloca(pid, "root");
749 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
764 *userns_fd = usernsfd;
769 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
774 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
775 if (userns_fd >= 0) {
776 /* Can't setns to your own userns, since then you could
777 * escalate from non-root to root in your own namespace, so
778 * check if namespaces equal before attempting to enter. */
779 _cleanup_free_ char *userns_fd_path = NULL;
781 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
784 r = files_same(userns_fd_path, "/proc/self/ns/user");
792 if (setns(pidns_fd, CLONE_NEWPID) < 0)
796 if (setns(mntns_fd, CLONE_NEWNS) < 0)
800 if (setns(netns_fd, CLONE_NEWNET) < 0)
804 if (setns(userns_fd, CLONE_NEWUSER) < 0)
808 if (fchdir(root_fd) < 0)
815 return reset_uid_gid();
818 uint64_t physical_memory(void) {
821 /* We return this as uint64_t in case we are running as 32bit
822 * process on a 64bit kernel with huge amounts of memory */
824 mem = sysconf(_SC_PHYS_PAGES);
827 return (uint64_t) mem * (uint64_t) page_size();
830 #if 0 /// UNNEEDED by elogind
831 int update_reboot_param_file(const char *param) {
835 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
837 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
839 (void) unlink(REBOOT_PARAM_FILE);
846 puts(PACKAGE_STRING "\n"