mirror of
https://github.com/systemd/systemd.git
synced 2024-10-31 16:21:26 +03:00
Merge pull request #7728 from poettering/fork-rework
some fork() reworking
This commit is contained in:
commit
95f7f85d39
4
TODO
4
TODO
@ -24,6 +24,10 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* add support for recursive bpf firewalling as supported by the newest kernel
|
||||
|
||||
* add bpf-based implementation of devices cgroup controller logic for compat with cgroupsv2 as supported by newest kernel
|
||||
|
||||
* implement transient socket unit.
|
||||
|
||||
* make systemd-run create transient path and socket unit.
|
||||
|
16
coccinelle/exit-0.cocci
Normal file
16
coccinelle/exit-0.cocci
Normal file
@ -0,0 +1,16 @@
|
||||
@@
|
||||
@@
|
||||
- exit(0);
|
||||
+ exit(EXIT_SUCCESS);
|
||||
@@
|
||||
@@
|
||||
- _exit(0);
|
||||
+ _exit(EXIT_SUCCESS);
|
||||
@@
|
||||
@@
|
||||
- exit(1);
|
||||
+ exit(EXIT_FAILURE);
|
||||
@@
|
||||
@@
|
||||
- _exit(1);
|
||||
+ _exit(EXIT_FAILURE);
|
@ -267,38 +267,23 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
|
||||
|
||||
static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
pid_t parent_pid, child_pid;
|
||||
pid_t child_pid;
|
||||
int r;
|
||||
|
||||
joined = strv_join(argv, " ");
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
parent_pid = getpid_cached();
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
|
||||
r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child_pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
/* In the child */
|
||||
if (child_pid == 0) {
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
/* Make sure the child goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
exec_process(child, argv, env, fd, 1);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_info("Spawned %s (%s) as PID %d", child, joined, child_pid);
|
||||
log_info("Spawned %s (%s) as PID " PID_FMT ".", child, joined, child_pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "fd-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "process-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int asynchronous_job(void* (*func)(void *p), void *arg) {
|
||||
@ -58,18 +60,29 @@ finish:
|
||||
return -r;
|
||||
}
|
||||
|
||||
static void *sync_thread(void *p) {
|
||||
sync();
|
||||
return NULL;
|
||||
}
|
||||
int asynchronous_sync(pid_t *ret_pid) {
|
||||
int r;
|
||||
|
||||
int asynchronous_sync(void) {
|
||||
log_debug("Spawning new thread for sync");
|
||||
/* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
|
||||
* disk. Note that we implement this as helper process rather than thread as we don't want the sync() to hang our
|
||||
* original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
|
||||
* syscalls. */
|
||||
|
||||
return asynchronous_job(sync_thread, NULL);
|
||||
r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, ret_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* Child process */
|
||||
(void) sync();
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *close_thread(void *p) {
|
||||
(void) pthread_setname_np(pthread_self(), "close");
|
||||
|
||||
assert_se(close_nointr(PTR_TO_FD(p)) != -EBADF);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -22,5 +22,5 @@
|
||||
|
||||
int asynchronous_job(void* (*func)(void *p), void *arg);
|
||||
|
||||
int asynchronous_sync(void);
|
||||
int asynchronous_sync(pid_t *ret_pid);
|
||||
int asynchronous_close(int fd);
|
||||
|
199
src/basic/blockdev-util.c
Normal file
199
src/basic/blockdev-util.c
Normal file
@ -0,0 +1,199 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "missing.h"
|
||||
#include "stat-util.h"
|
||||
|
||||
int block_get_whole_disk(dev_t d, dev_t *ret) {
|
||||
char p[SYS_BLOCK_PATH_MAX("/partition")];
|
||||
_cleanup_free_ char *s = NULL;
|
||||
unsigned n, m;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
/* If it has a queue this is good enough for us */
|
||||
xsprintf_sys_block_path(p, "/queue", d);
|
||||
if (access(p, F_OK) >= 0) {
|
||||
*ret = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If it is a partition find the originating device */
|
||||
xsprintf_sys_block_path(p, "/partition", d);
|
||||
if (access(p, F_OK) < 0)
|
||||
return -ENOENT;
|
||||
|
||||
/* Get parent dev_t */
|
||||
xsprintf_sys_block_path(p, "/../dev", d);
|
||||
r = read_one_line_file(p, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sscanf(s, "%u:%u", &m, &n);
|
||||
if (r != 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only return this if it is really good enough for us. */
|
||||
xsprintf_sys_block_path(p, "/queue", makedev(m, n));
|
||||
if (access(p, F_OK) < 0)
|
||||
return -ENOENT;
|
||||
|
||||
*ret = makedev(m, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_block_device(const char *path, dev_t *dev) {
|
||||
struct stat st;
|
||||
struct statfs sfs;
|
||||
|
||||
assert(path);
|
||||
assert(dev);
|
||||
|
||||
/* Get's the block device directly backing a file system. If
|
||||
* the block device is encrypted, returns the device mapper
|
||||
* block device. */
|
||||
|
||||
if (lstat(path, &st))
|
||||
return -errno;
|
||||
|
||||
if (major(st.st_dev) != 0) {
|
||||
*dev = st.st_dev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (statfs(path, &sfs) < 0)
|
||||
return -errno;
|
||||
|
||||
if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
|
||||
return btrfs_get_block_device(path, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
char p[SYS_BLOCK_PATH_MAX("/slaves")];
|
||||
struct dirent *de, *found = NULL;
|
||||
const char *q;
|
||||
unsigned maj, min;
|
||||
dev_t dt;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(dev);
|
||||
|
||||
/* Gets the backing block device for a file system, and
|
||||
* handles LUKS encrypted file systems, looking for its
|
||||
* immediate parent, if there is one. */
|
||||
|
||||
r = get_block_device(path, &dt);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
xsprintf_sys_block_path(p, "/slaves", dt);
|
||||
d = opendir(p);
|
||||
if (!d) {
|
||||
if (errno == ENOENT)
|
||||
goto fallback;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
FOREACH_DIRENT_ALL(de, d, return -errno) {
|
||||
|
||||
if (dot_or_dot_dot(de->d_name))
|
||||
continue;
|
||||
|
||||
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (found) {
|
||||
_cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
|
||||
|
||||
/* We found a device backed by multiple other devices. We don't really support automatic
|
||||
* discovery on such setups, with the exception of dm-verity partitions. In this case there are
|
||||
* two backing devices: the data partition and the hash partition. We are fine with such
|
||||
* setups, however, only if both partitions are on the same physical device. Hence, let's
|
||||
* verify this. */
|
||||
|
||||
u = strjoin(p, "/", de->d_name, "/../dev");
|
||||
if (!u)
|
||||
return -ENOMEM;
|
||||
|
||||
v = strjoin(p, "/", found->d_name, "/../dev");
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_one_line_file(u, &a);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", u);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
r = read_one_line_file(v, &b);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", v);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
/* Check if the parent device is the same. If not, then the two backing devices are on
|
||||
* different physical devices, and we don't support that. */
|
||||
if (!streq(a, b))
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
found = de;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto fallback;
|
||||
|
||||
q = strjoina(p, "/", found->d_name, "/dev");
|
||||
|
||||
r = read_one_line_file(q, &t);
|
||||
if (r == -ENOENT)
|
||||
goto fallback;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sscanf(t, "%u:%u", &maj, &min) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (maj == 0)
|
||||
goto fallback;
|
||||
|
||||
*dev = makedev(maj, min);
|
||||
return 1;
|
||||
|
||||
fallback:
|
||||
*dev = dt;
|
||||
return 1;
|
||||
}
|
38
src/basic/blockdev-util.h
Normal file
38
src/basic/blockdev-util.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
#define SYS_BLOCK_PATH_MAX(suffix) \
|
||||
(STRLEN("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen_ptr(suffix))
|
||||
#define xsprintf_sys_block_path(buf, suffix, devno) \
|
||||
xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix))
|
||||
|
||||
int block_get_whole_disk(dev_t d, dev_t *ret);
|
||||
|
||||
int get_block_device(const char *path, dev_t *dev);
|
||||
|
||||
int get_block_device_harder(const char *path, dev_t *dev);
|
@ -38,6 +38,7 @@
|
||||
#endif
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "btrfs-ctree.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "chattr-util.h"
|
||||
|
@ -1348,9 +1348,8 @@ typedef struct SpecNextResult {
|
||||
} SpecNextResult;
|
||||
|
||||
int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
|
||||
SpecNextResult *shared, tmp;
|
||||
pid_t pid;
|
||||
SpecNextResult *shared;
|
||||
SpecNextResult tmp;
|
||||
int r;
|
||||
|
||||
if (isempty(spec->timezone))
|
||||
@ -1360,15 +1359,12 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
|
||||
if (shared == MAP_FAILED)
|
||||
return negative_errno();
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
int fork_errno = errno;
|
||||
r = safe_fork("(sd-calendar)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0) {
|
||||
(void) munmap(shared, sizeof *shared);
|
||||
return -fork_errno;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
if (setenv("TZ", spec->timezone, 1) != 0) {
|
||||
shared->return_value = negative_errno();
|
||||
_exit(EXIT_FAILURE);
|
||||
|
@ -29,11 +29,6 @@
|
||||
int encode_devnode_name(const char *str, char *str_enc, size_t len);
|
||||
int whitelisted_char_for_devnode(char c, const char *additional);
|
||||
|
||||
#define SYS_BLOCK_PATH_MAX(suffix) \
|
||||
(STRLEN("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen_ptr(suffix))
|
||||
#define xsprintf_sys_block_path(buf, suffix, devno) \
|
||||
xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix))
|
||||
|
||||
#define DEV_NUM_PATH_MAX \
|
||||
(STRLEN("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t))
|
||||
#define xsprintf_dev_num_path(buf, type, devno) \
|
||||
|
@ -48,20 +48,19 @@ assert_cc(EAGAIN == EWOULDBLOCK);
|
||||
static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
|
||||
|
||||
pid_t _pid;
|
||||
int r;
|
||||
|
||||
if (null_or_empty_path(path)) {
|
||||
log_debug("%s is empty (a mask).", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_pid = fork();
|
||||
if (_pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
if (_pid == 0) {
|
||||
r = safe_fork("(direxec)", FORK_DEATHSIG, &_pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
char *_argv[2];
|
||||
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
if (stdout_fd >= 0) {
|
||||
/* If the fd happens to be in the right place, go along with that */
|
||||
if (stdout_fd != STDOUT_FILENO &&
|
||||
@ -107,11 +106,6 @@ static int do_execute(
|
||||
* If callbacks is nonnull, execution is serial. Otherwise, we default to parallel.
|
||||
*/
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -222,11 +216,10 @@ int execute_directories(
|
||||
* them to finish. Optionally a timeout is applied. If a file with the same name
|
||||
* exists in more than one directory, the earliest one wins. */
|
||||
|
||||
executor_pid = fork();
|
||||
if (executor_pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
|
||||
if (executor_pid == 0) {
|
||||
r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &executor_pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv);
|
||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -192,9 +192,9 @@ int fd_cloexec(int fd, bool cloexec) {
|
||||
}
|
||||
|
||||
void stdio_unset_cloexec(void) {
|
||||
fd_cloexec(STDIN_FILENO, false);
|
||||
fd_cloexec(STDOUT_FILENO, false);
|
||||
fd_cloexec(STDERR_FILENO, false);
|
||||
(void) fd_cloexec(STDIN_FILENO, false);
|
||||
(void) fd_cloexec(STDOUT_FILENO, false);
|
||||
(void) fd_cloexec(STDERR_FILENO, false);
|
||||
}
|
||||
|
||||
_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
|
||||
@ -227,20 +227,21 @@ int close_all_fds(const int except[], unsigned n_except) {
|
||||
|
||||
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
|
||||
for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
|
||||
int q;
|
||||
|
||||
if (fd_in_set(fd, except, n_except))
|
||||
continue;
|
||||
|
||||
if (close_nointr(fd) < 0)
|
||||
if (errno != EBADF && r == 0)
|
||||
r = -errno;
|
||||
q = close_nointr(fd);
|
||||
if (q < 0 && q != -EBADF && r >= 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
FOREACH_DIRENT(de, d, return -errno) {
|
||||
int fd = -1;
|
||||
int fd = -1, q;
|
||||
|
||||
if (safe_atoi(de->d_name, &fd) < 0)
|
||||
/* Let's better ignore this, just in case */
|
||||
@ -255,11 +256,9 @@ int close_all_fds(const int except[], unsigned n_except) {
|
||||
if (fd_in_set(fd, except, n_except))
|
||||
continue;
|
||||
|
||||
if (close_nointr(fd) < 0) {
|
||||
/* Valgrind has its own FD and doesn't want to have it closed */
|
||||
if (errno != EBADF && r == 0)
|
||||
r = -errno;
|
||||
}
|
||||
q = close_nointr(fd);
|
||||
if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
|
||||
r = q;
|
||||
}
|
||||
|
||||
return r;
|
||||
|
@ -35,6 +35,8 @@ basic_sources_plain = files('''
|
||||
bitmap.c
|
||||
bitmap.h
|
||||
blkid-util.h
|
||||
blockdev-util.c
|
||||
blockdev-util.h
|
||||
bpf-program.c
|
||||
bpf-program.h
|
||||
btrfs-ctree.h
|
||||
@ -203,10 +205,10 @@ basic_sources_plain = files('''
|
||||
time-util.h
|
||||
umask-util.h
|
||||
unaligned.h
|
||||
unit-name.c
|
||||
unit-name.h
|
||||
unit-def.c
|
||||
unit-def.h
|
||||
unit-name.c
|
||||
unit-name.h
|
||||
user-util.c
|
||||
user-util.h
|
||||
utf8.c
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "stat-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -296,10 +297,17 @@ int rename_process(const char name[]) {
|
||||
if (isempty(name))
|
||||
return -EINVAL; /* let's not confuse users unnecessarily with an empty name */
|
||||
|
||||
if (!is_main_thread())
|
||||
return -EPERM; /* Let's not allow setting the process name from other threads than the main one, as we
|
||||
* cache things without locking, and we make assumptions that PR_SET_NAME sets the
|
||||
* process name that isn't correct on any other threads */
|
||||
|
||||
l = strlen(name);
|
||||
|
||||
/* First step, change the comm field. */
|
||||
(void) prctl(PR_SET_NAME, name);
|
||||
/* First step, change the comm field. The main thread's comm is identical to the process comm. This means we
|
||||
* can use PR_SET_NAME, which sets the thread name for the calling thread. */
|
||||
if (prctl(PR_SET_NAME, name) < 0)
|
||||
log_debug_errno(errno, "PR_SET_NAME failed: %m");
|
||||
if (l > 15) /* Linux process names can be 15 chars at max */
|
||||
truncated = true;
|
||||
|
||||
@ -1134,6 +1142,213 @@ int must_be_root(void) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
int safe_fork_full(
|
||||
const char *name,
|
||||
const int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
pid_t *ret_pid) {
|
||||
|
||||
pid_t original_pid, pid;
|
||||
sigset_t saved_ss;
|
||||
bool block_signals;
|
||||
int r;
|
||||
|
||||
/* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
|
||||
* returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
|
||||
|
||||
original_pid = getpid_cached();
|
||||
|
||||
block_signals = flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG);
|
||||
|
||||
if (block_signals) {
|
||||
sigset_t ss;
|
||||
|
||||
/* We temporarily block all signals, so that the new child has them blocked initially. This way, we can be sure
|
||||
* that SIGTERMs are not lost we might send to the child. */
|
||||
if (sigfillset(&ss) < 0)
|
||||
return log_debug_errno(errno, "Failed to reset signal set: %m");
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
|
||||
return log_debug_errno(errno, "Failed to reset signal mask: %m");
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = -errno;
|
||||
|
||||
if (block_signals) /* undo what we did above */
|
||||
(void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
|
||||
|
||||
return log_debug_errno(r, "Failed to fork: %m");
|
||||
}
|
||||
if (pid > 0) {
|
||||
/* We are in the parent process */
|
||||
|
||||
if (block_signals) /* undo what we did above */
|
||||
(void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
|
||||
|
||||
log_debug("Sucessfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
|
||||
|
||||
if (ret_pid)
|
||||
*ret_pid = pid;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We are in the child process */
|
||||
|
||||
if (flags & FORK_REOPEN_LOG) {
|
||||
/* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */
|
||||
log_close();
|
||||
log_set_open_when_needed(true);
|
||||
}
|
||||
|
||||
if (name) {
|
||||
r = rename_process(name);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to rename process, ignoring: %m");
|
||||
}
|
||||
|
||||
if (flags & FORK_DEATHSIG)
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) {
|
||||
log_debug_errno(errno, "Failed to set death signal: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (flags & FORK_RESET_SIGNALS) {
|
||||
r = reset_all_signal_handlers();
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to reset signal handlers: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* This implicitly undoes the signal mask stuff we did before the fork()ing above */
|
||||
r = reset_signal_mask();
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to reset signal mask: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (block_signals) { /* undo what we did above */
|
||||
if (sigprocmask(SIG_SETMASK, &saved_ss, NULL) < 0) {
|
||||
log_debug_errno(errno, "Failed to restore signal mask: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_DEATHSIG) {
|
||||
/* Let's see if the parent PID is still the one we started from? If not, then the parent
|
||||
* already died by the time we set PR_SET_PDEATHSIG, hence let's emulate the effect */
|
||||
|
||||
if (getppid() != original_pid) {
|
||||
log_debug("Parent died early, raising SIGTERM.");
|
||||
(void) raise(SIGTERM);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_CLOSE_ALL_FDS) {
|
||||
/* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */
|
||||
log_close();
|
||||
|
||||
r = close_all_fds(except_fds, n_except_fds);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to close all file descriptors: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* When we were asked to reopen the logs, do so again now */
|
||||
if (flags & FORK_REOPEN_LOG) {
|
||||
log_open();
|
||||
log_set_open_when_needed(false);
|
||||
}
|
||||
|
||||
if (flags & FORK_NULL_STDIO) {
|
||||
r = make_null_stdio();
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to connect stdin/stdout to /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_pid)
|
||||
*ret_pid = getpid_cached();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *ret_pid, const char *path, ...) {
|
||||
bool stdout_is_tty, stderr_is_tty;
|
||||
unsigned n, i;
|
||||
va_list ap;
|
||||
char **l;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Spawns a temporary TTY agent, making sure it goes away when we go away */
|
||||
|
||||
r = safe_fork_full(name, except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, ret_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
/* In the child: */
|
||||
|
||||
stdout_is_tty = isatty(STDOUT_FILENO);
|
||||
stderr_is_tty = isatty(STDERR_FILENO);
|
||||
|
||||
if (!stdout_is_tty || !stderr_is_tty) {
|
||||
int fd;
|
||||
|
||||
/* Detach from stdout/stderr. and reopen
|
||||
* /dev/tty for them. This is important to
|
||||
* ensure that when systemctl is started via
|
||||
* popen() or a similar call that expects to
|
||||
* read EOF we actually do generate EOF and
|
||||
* not delay this indefinitely by because we
|
||||
* keep an unused copy of stdin around. */
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
log_error_errno(errno, "Failed to open /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
|
||||
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
|
||||
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Count arguments */
|
||||
va_start(ap, path);
|
||||
for (n = 0; va_arg(ap, char*); n++)
|
||||
;
|
||||
va_end(ap);
|
||||
|
||||
/* Allocate strv */
|
||||
l = alloca(sizeof(char *) * (n + 1));
|
||||
|
||||
/* Fill in arguments */
|
||||
va_start(ap, path);
|
||||
for (i = 0; i <= n; i++)
|
||||
l[i] = va_arg(ap, char*);
|
||||
va_end(ap);
|
||||
|
||||
execv(path, l);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
|
@ -142,3 +142,19 @@ int ioprio_parse_priority(const char *s, int *ret);
|
||||
pid_t getpid_cached(void);
|
||||
|
||||
int must_be_root(void);
|
||||
|
||||
typedef enum ForkFlags {
|
||||
FORK_RESET_SIGNALS = 1U << 0,
|
||||
FORK_CLOSE_ALL_FDS = 1U << 1,
|
||||
FORK_DEATHSIG = 1U << 2,
|
||||
FORK_NULL_STDIO = 1U << 3,
|
||||
FORK_REOPEN_LOG = 1U << 4,
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||
|
||||
static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
||||
return safe_fork_full(name, NULL, 0, flags, ret_pid);
|
||||
}
|
||||
|
||||
int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *pid, const char *path, ...);
|
||||
|
@ -875,31 +875,30 @@ bool on_tty(void) {
|
||||
}
|
||||
|
||||
int make_stdio(int fd) {
|
||||
int r, s, t;
|
||||
int r = 0;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
r = dup2(fd, STDIN_FILENO);
|
||||
s = dup2(fd, STDOUT_FILENO);
|
||||
t = dup2(fd, STDERR_FILENO);
|
||||
if (dup2(fd, STDIN_FILENO) < 0 && r >= 0)
|
||||
r = -errno;
|
||||
if (dup2(fd, STDOUT_FILENO) < 0 && r >= 0)
|
||||
r = -errno;
|
||||
if (dup2(fd, STDERR_FILENO) < 0 && r >= 0)
|
||||
r = -errno;
|
||||
|
||||
if (fd >= 3)
|
||||
safe_close(fd);
|
||||
|
||||
if (r < 0 || s < 0 || t < 0)
|
||||
return -errno;
|
||||
|
||||
/* Explicitly unset O_CLOEXEC, since if fd was < 3, then
|
||||
* dup2() was a NOP and the bit hence possibly set. */
|
||||
/* Explicitly unset O_CLOEXEC, since if fd was < 3, then dup2() was a NOP and the bit hence possibly set. */
|
||||
stdio_unset_cloexec();
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int make_null_stdio(void) {
|
||||
int null_fd;
|
||||
|
||||
null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
|
||||
null_fd = open("/dev/null", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
||||
if (null_fd < 0)
|
||||
return -errno;
|
||||
|
||||
@ -1107,11 +1106,10 @@ int openpt_in_namespace(pid_t pid, int flags) {
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return -errno;
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-openpt)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
int master;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
@ -1158,11 +1156,10 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return -errno;
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-terminal)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
int master;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
@ -886,8 +886,8 @@ typedef struct ParseTimestampResult {
|
||||
int parse_timestamp(const char *t, usec_t *usec) {
|
||||
char *last_space, *tz = NULL;
|
||||
ParseTimestampResult *shared, tmp;
|
||||
int r;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
last_space = strrchr(t, ' ');
|
||||
if (last_space != NULL && timezone_is_valid(last_space + 1))
|
||||
@ -900,15 +900,12 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
if (shared == MAP_FAILED)
|
||||
return negative_errno();
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
int fork_errno = errno;
|
||||
r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0) {
|
||||
(void) munmap(shared, sizeof *shared);
|
||||
return -fork_errno;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
bool with_tz = true;
|
||||
|
||||
if (setenv("TZ", tz, 1) != 0) {
|
||||
|
274
src/basic/util.c
274
src/basic/util.c
@ -118,45 +118,6 @@ int socket_from_display(const char *display, char **path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int block_get_whole_disk(dev_t d, dev_t *ret) {
|
||||
char p[SYS_BLOCK_PATH_MAX("/partition")];
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
unsigned n, m;
|
||||
|
||||
assert(ret);
|
||||
|
||||
/* If it has a queue this is good enough for us */
|
||||
xsprintf_sys_block_path(p, "/queue", d);
|
||||
if (access(p, F_OK) >= 0) {
|
||||
*ret = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If it is a partition find the originating device */
|
||||
xsprintf_sys_block_path(p, "/partition", d);
|
||||
if (access(p, F_OK) < 0)
|
||||
return -ENOENT;
|
||||
|
||||
/* Get parent dev_t */
|
||||
xsprintf_sys_block_path(p, "/../dev", d);
|
||||
r = read_one_line_file(p, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sscanf(s, "%u:%u", &m, &n);
|
||||
if (r != 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only return this if it is really good enough for us. */
|
||||
xsprintf_sys_block_path(p, "/queue", makedev(m, n));
|
||||
if (access(p, F_OK) < 0)
|
||||
return -ENOENT;
|
||||
|
||||
*ret = makedev(m, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool kexec_loaded(void) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
@ -184,112 +145,6 @@ int prot_from_flags(int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
|
||||
bool stdout_is_tty, stderr_is_tty;
|
||||
pid_t parent_pid, agent_pid;
|
||||
sigset_t ss, saved_ss;
|
||||
unsigned n, i;
|
||||
va_list ap;
|
||||
char **l;
|
||||
|
||||
assert(pid);
|
||||
assert(path);
|
||||
|
||||
/* Spawns a temporary TTY agent, making sure it goes away when
|
||||
* we go away */
|
||||
|
||||
parent_pid = getpid_cached();
|
||||
|
||||
/* First we temporarily block all signals, so that the new
|
||||
* child has them blocked initially. This way, we can be sure
|
||||
* that SIGTERMs are not lost we might send to the agent. */
|
||||
assert_se(sigfillset(&ss) >= 0);
|
||||
assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
|
||||
|
||||
agent_pid = fork();
|
||||
if (agent_pid < 0) {
|
||||
assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (agent_pid != 0) {
|
||||
assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
|
||||
*pid = agent_pid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In the child:
|
||||
*
|
||||
* Make sure the agent goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Make sure we actually can kill the agent, if we need to, in
|
||||
* case somebody invoked us from a shell script that trapped
|
||||
* SIGTERM or so... */
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal and unblock the signals */
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
/* Don't leak fds to the agent */
|
||||
close_all_fds(except, n_except);
|
||||
|
||||
stdout_is_tty = isatty(STDOUT_FILENO);
|
||||
stderr_is_tty = isatty(STDERR_FILENO);
|
||||
|
||||
if (!stdout_is_tty || !stderr_is_tty) {
|
||||
int fd;
|
||||
|
||||
/* Detach from stdout/stderr. and reopen
|
||||
* /dev/tty for them. This is important to
|
||||
* ensure that when systemctl is started via
|
||||
* popen() or a similar call that expects to
|
||||
* read EOF we actually do generate EOF and
|
||||
* not delay this indefinitely by because we
|
||||
* keep an unused copy of stdin around. */
|
||||
fd = open("/dev/tty", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
log_error_errno(errno, "Failed to open /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
|
||||
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
|
||||
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (fd > STDERR_FILENO)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* Count arguments */
|
||||
va_start(ap, path);
|
||||
for (n = 0; va_arg(ap, char*); n++)
|
||||
;
|
||||
va_end(ap);
|
||||
|
||||
/* Allocate strv */
|
||||
l = alloca(sizeof(char *) * (n + 1));
|
||||
|
||||
/* Fill in arguments */
|
||||
va_start(ap, path);
|
||||
for (i = 0; i <= n; i++)
|
||||
l[i] = va_arg(ap, char*);
|
||||
va_end(ap);
|
||||
|
||||
execv(path, l);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
bool in_initrd(void) {
|
||||
struct statfs s;
|
||||
|
||||
@ -698,132 +553,3 @@ int version(void) {
|
||||
SYSTEMD_FEATURES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_block_device(const char *path, dev_t *dev) {
|
||||
struct stat st;
|
||||
struct statfs sfs;
|
||||
|
||||
assert(path);
|
||||
assert(dev);
|
||||
|
||||
/* Get's the block device directly backing a file system. If
|
||||
* the block device is encrypted, returns the device mapper
|
||||
* block device. */
|
||||
|
||||
if (lstat(path, &st))
|
||||
return -errno;
|
||||
|
||||
if (major(st.st_dev) != 0) {
|
||||
*dev = st.st_dev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (statfs(path, &sfs) < 0)
|
||||
return -errno;
|
||||
|
||||
if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
|
||||
return btrfs_get_block_device(path, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
char p[SYS_BLOCK_PATH_MAX("/slaves")];
|
||||
struct dirent *de, *found = NULL;
|
||||
const char *q;
|
||||
unsigned maj, min;
|
||||
dev_t dt;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(dev);
|
||||
|
||||
/* Gets the backing block device for a file system, and
|
||||
* handles LUKS encrypted file systems, looking for its
|
||||
* immediate parent, if there is one. */
|
||||
|
||||
r = get_block_device(path, &dt);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
xsprintf_sys_block_path(p, "/slaves", dt);
|
||||
d = opendir(p);
|
||||
if (!d) {
|
||||
if (errno == ENOENT)
|
||||
goto fallback;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
FOREACH_DIRENT_ALL(de, d, return -errno) {
|
||||
|
||||
if (dot_or_dot_dot(de->d_name))
|
||||
continue;
|
||||
|
||||
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (found) {
|
||||
_cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
|
||||
|
||||
/* We found a device backed by multiple other devices. We don't really support automatic
|
||||
* discovery on such setups, with the exception of dm-verity partitions. In this case there are
|
||||
* two backing devices: the data partition and the hash partition. We are fine with such
|
||||
* setups, however, only if both partitions are on the same physical device. Hence, let's
|
||||
* verify this. */
|
||||
|
||||
u = strjoin(p, "/", de->d_name, "/../dev");
|
||||
if (!u)
|
||||
return -ENOMEM;
|
||||
|
||||
v = strjoin(p, "/", found->d_name, "/../dev");
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_one_line_file(u, &a);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", u);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
r = read_one_line_file(v, &b);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", v);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
/* Check if the parent device is the same. If not, then the two backing devices are on
|
||||
* different physical devices, and we don't support that. */
|
||||
if (!streq(a, b))
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
found = de;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto fallback;
|
||||
|
||||
q = strjoina(p, "/", found->d_name, "/dev");
|
||||
|
||||
r = read_one_line_file(q, &t);
|
||||
if (r == -ENOENT)
|
||||
goto fallback;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sscanf(t, "%u:%u", &maj, &min) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (maj == 0)
|
||||
goto fallback;
|
||||
|
||||
*dev = makedev(maj, min);
|
||||
return 1;
|
||||
|
||||
fallback:
|
||||
*dev = dt;
|
||||
return 1;
|
||||
}
|
||||
|
@ -71,8 +71,6 @@ bool plymouth_running(void);
|
||||
bool display_is_local(const char *display) _pure_;
|
||||
int socket_from_display(const char *display, char **path);
|
||||
|
||||
int block_get_whole_disk(dev_t d, dev_t *ret);
|
||||
|
||||
#define NULSTR_FOREACH(i, l) \
|
||||
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
|
||||
|
||||
@ -86,8 +84,6 @@ bool kexec_loaded(void);
|
||||
|
||||
int prot_from_flags(int flags) _const_;
|
||||
|
||||
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);
|
||||
|
||||
bool in_initrd(void);
|
||||
void in_initrd_force(bool value);
|
||||
|
||||
@ -193,6 +189,3 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
|
||||
int update_reboot_parameter_and_warn(const char *param);
|
||||
|
||||
int version(void);
|
||||
|
||||
int get_block_device(const char *path, dev_t *dev);
|
||||
int get_block_device_harder(const char *path, dev_t *dev);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "bpf-firewall.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "cgroup.h"
|
||||
@ -307,7 +308,7 @@ static int lookup_block_device(const char *p, dev_t *dev) {
|
||||
|
||||
/* If this is a partition, try to get the originating
|
||||
* block device */
|
||||
block_get_whole_disk(*dev, dev);
|
||||
(void) block_get_whole_disk(*dev, dev);
|
||||
} else {
|
||||
log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
|
||||
return -ENODEV;
|
||||
|
@ -1207,27 +1207,19 @@ static int setup_pam(
|
||||
|
||||
parent_pid = getpid_cached();
|
||||
|
||||
pam_pid = fork();
|
||||
if (pam_pid < 0) {
|
||||
r = -errno;
|
||||
r = safe_fork("(sd-pam)", 0, &pam_pid);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pam_pid == 0) {
|
||||
if (r == 0) {
|
||||
int sig, ret = EXIT_PAM;
|
||||
|
||||
/* The child's job is to reset the PAM session on
|
||||
* termination */
|
||||
barrier_set_role(&barrier, BARRIER_CHILD);
|
||||
|
||||
/* This string must fit in 10 chars (i.e. the length
|
||||
* of "/sbin/init"), to look pretty in /bin/ps */
|
||||
rename_process("(sd-pam)");
|
||||
|
||||
/* Make sure we don't keep open the passed fds in this
|
||||
child. We assume that otherwise only those fds are
|
||||
open here that have been opened by PAM. */
|
||||
close_many(fds, n_fds);
|
||||
/* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds
|
||||
* are open here that have been opened by PAM. */
|
||||
(void) close_many(fds, n_fds);
|
||||
|
||||
/* Drop privileges - we don't need any to pam_close_session
|
||||
* and this will make PR_SET_PDEATHSIG work in most cases.
|
||||
@ -1879,11 +1871,10 @@ static int setup_private_users(uid_t uid, gid_t gid) {
|
||||
if (pipe2(errno_pipe, O_CLOEXEC) < 0)
|
||||
return -errno;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return -errno;
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
const char *a;
|
||||
pid_t ppid;
|
||||
|
@ -1244,7 +1244,7 @@ void job_shutdown_magic(Job *j) {
|
||||
if (detect_container() > 0)
|
||||
return;
|
||||
|
||||
asynchronous_sync();
|
||||
(void) asynchronous_sync(NULL);
|
||||
}
|
||||
|
||||
int job_get_timeout(Job *j, usec_t *timeout) {
|
||||
|
@ -1457,7 +1457,7 @@ static void redirect_telinit(int argc, char *argv[]) {
|
||||
|
||||
execv(SYSTEMCTL_BINARY_PATH, argv);
|
||||
log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -31,10 +31,11 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "async.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "def.h"
|
||||
#include "exec-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "killall.h"
|
||||
#include "log.h"
|
||||
@ -211,26 +212,20 @@ static bool sync_making_progress(unsigned long long *prev_dirty) {
|
||||
}
|
||||
|
||||
static void sync_with_progress(void) {
|
||||
unsigned long long dirty = ULONG_LONG_MAX;
|
||||
unsigned checks;
|
||||
pid_t pid;
|
||||
int r;
|
||||
unsigned long long dirty = ULONG_LONG_MAX;
|
||||
|
||||
BLOCK_SIGNALS(SIGCHLD);
|
||||
|
||||
/* Due to the possiblity of the sync operation hanging, we fork
|
||||
* a child process and monitor the progress. If the timeout
|
||||
* lapses, the assumption is that that particular sync stalled. */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
log_error_errno(errno, "Failed to fork: %m");
|
||||
return;
|
||||
}
|
||||
/* Due to the possiblity of the sync operation hanging, we fork a child process and monitor the progress. If
|
||||
* the timeout lapses, the assumption is that that particular sync stalled. */
|
||||
|
||||
if (pid == 0) {
|
||||
/* Start the sync operation here in the child */
|
||||
sync();
|
||||
_exit(EXIT_SUCCESS);
|
||||
r = asynchronous_sync(&pid);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to fork sync(): %m");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Syncing filesystems and block devices.");
|
||||
@ -492,10 +487,10 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
log_info("Rebooting with kexec.");
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
log_error_errno(errno, "Failed to fork: %m");
|
||||
else if (pid == 0) {
|
||||
r = safe_fork("(sd-kexec)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
|
||||
const char * const args[] = {
|
||||
KEXEC, "-e", NULL
|
||||
@ -505,8 +500,9 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
execv(args[0], (char * const *) args);
|
||||
_exit(EXIT_FAILURE);
|
||||
} else
|
||||
wait_for_terminate_and_warn("kexec", pid, true);
|
||||
}
|
||||
|
||||
(void) wait_for_terminate_and_warn("kexec", pid, true);
|
||||
}
|
||||
|
||||
cmd = RB_AUTOBOOT;
|
||||
@ -548,7 +544,7 @@ int main(int argc, char *argv[]) {
|
||||
* CAP_SYS_BOOT just exit, this will kill our
|
||||
* container for good. */
|
||||
log_info("Exiting container.");
|
||||
exit(0);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
r = log_error_errno(errno, "Failed to invoke reboot(): %m");
|
||||
|
@ -1527,7 +1527,7 @@ static int socket_address_listen_in_cgroup(
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
|
||||
return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
|
||||
|
||||
r = unit_fork_helper_process(UNIT(s), &pid);
|
||||
r = unit_fork_helper_process(UNIT(s), "(sd-listen)", &pid);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(UNIT(s), r, "Failed to fork off listener stub process: %m");
|
||||
if (r == 0) {
|
||||
@ -1944,7 +1944,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
|
||||
/* We have to resolve the user names out-of-process, hence
|
||||
* let's fork here. It's messy, but well, what can we do? */
|
||||
|
||||
r = unit_fork_helper_process(UNIT(s), &pid);
|
||||
r = unit_fork_helper_process(UNIT(s), "(sd-chown)", &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
@ -2871,7 +2871,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
|
||||
return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
|
||||
|
||||
r = unit_fork_helper_process(UNIT(s), &pid);
|
||||
r = unit_fork_helper_process(UNIT(s), "(sd-accept)", &pid);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(UNIT(s), r, "Failed to fork off accept stub process: %m");
|
||||
if (r == 0) {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "libudev.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "def.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
@ -35,12 +36,12 @@
|
||||
#include "linux-3.13/dm-ioctl.h"
|
||||
#include "list.h"
|
||||
#include "mount-setup.h"
|
||||
#include "mount-util.h"
|
||||
#include "path-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
#include "udev-util.h"
|
||||
#include "umount.h"
|
||||
#include "mount-util.h"
|
||||
#include "util.h"
|
||||
#include "virt.h"
|
||||
|
||||
@ -388,11 +389,10 @@ static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
|
||||
* fork a child process and set a timeout. If the timeout
|
||||
* lapses, the assumption is that that particular remount
|
||||
* failed. */
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(sd-remount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
log_info("Remounting '%s' read-only in with options '%s'.", m->path, options);
|
||||
|
||||
/* Start the mount operation here in the child */
|
||||
@ -423,11 +423,10 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
|
||||
* fork a child process and set a timeout. If the timeout
|
||||
* lapses, the assumption is that that particular umount
|
||||
* failed. */
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(sd-umount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
log_info("Unmounting '%s'.", m->path);
|
||||
|
||||
/* Start the mount operation here in the child Using MNT_FORCE
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -4968,8 +4969,7 @@ void unit_set_exec_params(Unit *u, ExecParameters *p) {
|
||||
SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, UNIT_CGROUP_BOOL(u, delegate));
|
||||
}
|
||||
|
||||
int unit_fork_helper_process(Unit *u, pid_t *ret) {
|
||||
pid_t pid;
|
||||
int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
@ -4980,17 +4980,14 @@ int unit_fork_helper_process(Unit *u, pid_t *ret) {
|
||||
|
||||
(void) unit_realize_cgroup(u);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return -errno;
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork(name, FORK_REOPEN_LOG, ret);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
(void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
|
||||
(void) ignore_signals(SIGPIPE, -1);
|
||||
|
||||
log_close();
|
||||
log_open();
|
||||
(void) prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
|
||||
if (u->cgroup_path) {
|
||||
r = cg_attach_everywhere(u->manager->cgroup_supported, u->cgroup_path, 0, NULL, NULL);
|
||||
@ -5000,12 +4997,7 @@ int unit_fork_helper_process(Unit *u, pid_t *ret) {
|
||||
}
|
||||
}
|
||||
|
||||
*ret = getpid_cached();
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ret = pid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void unit_update_dependency_mask(Unit *u, UnitDependency d, Unit *other, UnitDependencyInfo di) {
|
||||
|
@ -782,7 +782,7 @@ bool unit_shall_confirm_spawn(Unit *u);
|
||||
|
||||
void unit_set_exec_params(Unit *s, ExecParameters *p);
|
||||
|
||||
int unit_fork_helper_process(Unit *u, pid_t *ret);
|
||||
int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret);
|
||||
|
||||
void unit_remove_dependencies(Unit *u, UnitDependencyMask mask);
|
||||
|
||||
|
@ -928,19 +928,15 @@ static int run_gdb(sd_journal *j) {
|
||||
/* Don't interfere with gdb and its handling of SIGINT. */
|
||||
(void) ignore_signals(SIGINT, -1);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = log_error_errno(errno, "Failed to fork(): %m");
|
||||
r = safe_fork("(gdb)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to fork(): %m");
|
||||
goto finish;
|
||||
}
|
||||
if (pid == 0) {
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
if (r == 0) {
|
||||
execlp("gdb", "gdb", exe, path, NULL);
|
||||
|
||||
log_error_errno(errno, "Failed to invoke gdb: %m");
|
||||
_exit(1);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = wait_for_terminate(pid, &st);
|
||||
|
@ -161,8 +161,8 @@ static int notify_override_unchanged(const char *f) {
|
||||
|
||||
static int found_override(const char *top, const char *bottom) {
|
||||
_cleanup_free_ char *dest = NULL;
|
||||
int k;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert(top);
|
||||
assert(bottom);
|
||||
@ -170,31 +170,26 @@ static int found_override(const char *top, const char *bottom) {
|
||||
if (null_or_empty_path(top) > 0)
|
||||
return notify_override_masked(top, bottom);
|
||||
|
||||
k = readlink_malloc(top, &dest);
|
||||
if (k >= 0) {
|
||||
r = readlink_malloc(top, &dest);
|
||||
if (r >= 0) {
|
||||
if (equivalent(dest, bottom) > 0)
|
||||
return notify_override_equivalent(top, bottom);
|
||||
else
|
||||
return notify_override_redirected(top, bottom);
|
||||
}
|
||||
|
||||
k = notify_override_overridden(top, bottom);
|
||||
r = notify_override_overridden(top, bottom);
|
||||
if (!arg_diff)
|
||||
return k;
|
||||
return r;
|
||||
|
||||
putchar('\n');
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork off diff: %m");
|
||||
else if (pid == 0) {
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(pid, "Failed to fork off diff: %m");
|
||||
if (r == 0) {
|
||||
execlp("diff", "diff", "-us", "--", bottom, top, NULL);
|
||||
log_error_errno(errno, "Failed to execute diff: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
@ -203,7 +198,7 @@ static int found_override(const char *top, const char *bottom) {
|
||||
wait_for_terminate_and_warn("diff", pid, false);
|
||||
putchar('\n');
|
||||
|
||||
return k;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int enumerate_dir_d(
|
||||
|
@ -392,12 +392,12 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = log_error_errno(errno, "fork(): %m");
|
||||
r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "fork(): %m");
|
||||
goto finish;
|
||||
}
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
char dash_c[STRLEN("-C") + DECIMAL_STR_MAX(int) + 1];
|
||||
int progress_socket = -1;
|
||||
const char *cmdline[9];
|
||||
@ -405,10 +405,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
/* Close the reading side of the progress pipe */
|
||||
progress_pipe[0] = safe_close(progress_pipe[0]);
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "blkid-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "dissect-image.h"
|
||||
|
@ -82,11 +82,10 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
|
||||
if (pipe2(pipefd, O_CLOEXEC) < 0)
|
||||
return log_error_errno(errno, "Failed to create pipe for tar: %m");
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork off tar: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork off tar: %m");
|
||||
if (r == 0) {
|
||||
int null_fd;
|
||||
uint64_t retain =
|
||||
(1ULL << CAP_CHOWN) |
|
||||
@ -98,10 +97,6 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
pipefd[1] = safe_close(pipefd[1]);
|
||||
|
||||
r = move_fd(pipefd[0], STDIN_FILENO, false);
|
||||
@ -156,20 +151,15 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
|
||||
if (pipe2(pipefd, O_CLOEXEC) < 0)
|
||||
return log_error_errno(errno, "Failed to create pipe for tar: %m");
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork off tar: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork off tar: %m");
|
||||
if (r == 0) {
|
||||
int null_fd;
|
||||
uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
pipefd[0] = safe_close(pipefd[0]);
|
||||
|
||||
r = move_fd(pipefd[1], STDOUT_FILENO, false);
|
||||
|
@ -371,10 +371,10 @@ static int transfer_start(Transfer *t) {
|
||||
if (pipe2(pipefd, O_CLOEXEC) < 0)
|
||||
return -errno;
|
||||
|
||||
t->pid = fork();
|
||||
if (t->pid < 0)
|
||||
return -errno;
|
||||
if (t->pid == 0) {
|
||||
r = safe_fork("(sd-transfer)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &t->pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
const char *cmd[] = {
|
||||
NULL, /* systemd-import, systemd-export or systemd-pull */
|
||||
NULL, /* tar, raw */
|
||||
@ -393,10 +393,6 @@ static int transfer_start(Transfer *t) {
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
pipefd[0] = safe_close(pipefd[0]);
|
||||
|
||||
if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
|
||||
|
@ -463,10 +463,10 @@ int pull_verify(PullJob *main_job,
|
||||
|
||||
gpg_home_created = true;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork off gpg: %m");
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(gpg)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork off gpg: %m");
|
||||
if (r == 0) {
|
||||
const char *cmd[] = {
|
||||
"gpg",
|
||||
"--no-options",
|
||||
@ -487,10 +487,6 @@ int pull_verify(PullJob *main_job,
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
gpg_pipe[1] = safe_close(gpg_pipe[1]);
|
||||
|
||||
r = move_fd(gpg_pipe[0], STDIN_FILENO, false);
|
||||
|
@ -81,27 +81,20 @@ static bool arg_trust_all = false;
|
||||
**********************************************************************/
|
||||
|
||||
static int spawn_child(const char* child, char** argv) {
|
||||
int fd[2];
|
||||
pid_t parent_pid, child_pid;
|
||||
int r;
|
||||
pid_t child_pid;
|
||||
int fd[2], r;
|
||||
|
||||
if (pipe(fd) < 0)
|
||||
return log_error_errno(errno, "Failed to create pager pipe: %m");
|
||||
|
||||
parent_pid = getpid_cached();
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
r = log_error_errno(errno, "Failed to fork: %m");
|
||||
r = safe_fork("(remote)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child_pid);
|
||||
if (r < 0) {
|
||||
safe_close_pair(fd);
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
}
|
||||
|
||||
/* In the child */
|
||||
if (child_pid == 0) {
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
if (r == 0) {
|
||||
|
||||
r = dup2(fd[1], STDOUT_FILENO);
|
||||
if (r < 0) {
|
||||
@ -111,15 +104,6 @@ static int spawn_child(const char* child, char** argv) {
|
||||
|
||||
safe_close_pair(fd);
|
||||
|
||||
/* Make sure the child goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
execvp(child, argv);
|
||||
log_error_errno(errno, "Failed to exec child %s: %m", child);
|
||||
_exit(EXIT_FAILURE);
|
||||
|
@ -147,6 +147,8 @@ static void journal_file_set_offline_internal(JournalFile *f) {
|
||||
static void * journal_file_set_offline_thread(void *arg) {
|
||||
JournalFile *f = arg;
|
||||
|
||||
(void) pthread_setname_np(pthread_self(), "journal-offline");
|
||||
|
||||
journal_file_set_offline_internal(f);
|
||||
|
||||
return NULL;
|
||||
|
@ -62,11 +62,10 @@ int bus_container_connect_socket(sd_bus *b) {
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return -errno;
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
pid_t grandchild;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
@ -82,11 +81,10 @@ int bus_container_connect_socket(sd_bus *b) {
|
||||
* comes from a process from within the container, and
|
||||
* not outside of it */
|
||||
|
||||
grandchild = fork();
|
||||
if (grandchild < 0)
|
||||
r = safe_fork("(sd-buscntr2)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &grandchild);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
if (grandchild == 0) {
|
||||
if (r == 0) {
|
||||
|
||||
r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
|
||||
if (r < 0) {
|
||||
|
@ -715,19 +715,14 @@ int bus_socket_exec(sd_bus *b) {
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = safe_fork_full("(sd-busexec)", s+1, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0) {
|
||||
safe_close_pair(s);
|
||||
return -errno;
|
||||
return r;
|
||||
}
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
close_all_fds(s+1, 1);
|
||||
|
||||
assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
|
||||
assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
|
||||
|
||||
|
@ -319,7 +319,7 @@ int main(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
|
@ -97,7 +97,7 @@ static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si,
|
||||
assert_se(pid >= 0);
|
||||
|
||||
if (pid == 0)
|
||||
_exit(0);
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
assert_se(sd_event_add_child(sd_event_source_get_event(s), &p, pid, WEXITED, child_handler, INT_TO_PTR('f')) >= 0);
|
||||
assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
|
||||
|
@ -405,7 +405,7 @@ static void* thread_worker(void *p) {
|
||||
assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0);
|
||||
|
||||
/* Assign a pretty name to this thread */
|
||||
(void) prctl(PR_SET_NAME, (unsigned long) "sd-resolve");
|
||||
(void) pthread_setname_np(pthread_self(), "sd-resolve");
|
||||
|
||||
while (!resolve->dead) {
|
||||
union {
|
||||
|
@ -266,20 +266,13 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
log_error_errno(errno, "Failed to fork: %m");
|
||||
r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to fork: %m");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
close_all_fds(NULL, 0);
|
||||
|
||||
execvp(argv[optind], argv + optind);
|
||||
log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
|
||||
_exit(EXIT_FAILURE);
|
||||
|
@ -75,10 +75,10 @@ int bus_image_method_remove(
|
||||
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
r = image_remove(image);
|
||||
@ -187,10 +187,10 @@ int bus_image_method_clone(
|
||||
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
if (child == 0) {
|
||||
r = safe_fork("(imgclone)", FORK_RESET_SIGNALS, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
|
||||
|
||||
r = image_clone(image, new_name, read_only);
|
||||
|
@ -250,11 +250,10 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-addr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
_cleanup_free_ struct local_address *addresses = NULL;
|
||||
struct local_address *a;
|
||||
int i, n;
|
||||
@ -390,11 +389,10 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
|
||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-osrel)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
int fd = -1;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
@ -997,13 +995,12 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
|
||||
goto finish;
|
||||
}
|
||||
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child);
|
||||
if (r < 0) {
|
||||
sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (child == 0) {
|
||||
if (r == 0) {
|
||||
const char *mount_inside;
|
||||
int mntfd;
|
||||
const char *q;
|
||||
@ -1172,11 +1169,10 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
|
||||
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
int containerfd;
|
||||
const char *q;
|
||||
int mntfd;
|
||||
@ -1282,11 +1278,10 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
_cleanup_close_ int dfd = -1;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
@ -1078,11 +1078,10 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
|
||||
return -errno;
|
||||
|
||||
/* This might be a slow operation, run it asynchronously in a background process */
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-clean)", FORK_RESET_SIGNALS, &child);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
|
||||
if (r == 0) {
|
||||
_cleanup_(image_hashmap_freep) Hashmap *images = NULL;
|
||||
bool success = true;
|
||||
Image *image;
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "util.h"
|
||||
|
||||
static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
|
||||
int pipe_fds[2];
|
||||
int pipe_fds[2], r;
|
||||
pid_t pid;
|
||||
|
||||
assert(database);
|
||||
@ -43,10 +43,10 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
|
||||
if (pipe2(pipe_fds, O_CLOEXEC) < 0)
|
||||
return log_error_errno(errno, "Failed to allocate pipe: %m");
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork getent child: %m");
|
||||
else if (pid == 0) {
|
||||
r = safe_fork("(getent)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork getent child: %m");
|
||||
if (r == 0) {
|
||||
int nullfd;
|
||||
char *empty_env = NULL;
|
||||
|
||||
@ -71,8 +71,6 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
|
||||
if (nullfd > 2)
|
||||
safe_close(nullfd);
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
close_all_fds(NULL, 0);
|
||||
|
||||
execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
|
||||
|
@ -93,7 +93,7 @@ int stub_pid1(sd_id128_t uuid) {
|
||||
sd_id128_to_string(uuid, new_environment + sizeof(new_environment) - SD_ID128_STRING_MAX);
|
||||
reset_environ(new_environment, sizeof(new_environment));
|
||||
|
||||
rename_process("STUBINIT");
|
||||
(void) rename_process("(sd-stubinit)");
|
||||
|
||||
assert_se(sigemptyset(&waitmask) >= 0);
|
||||
assert_se(sigset_add_many(&waitmask,
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
|
||||
#include "blockdev-util.h"
|
||||
#include "crypt-util.h"
|
||||
#include "device-nodes.h"
|
||||
#include "dissect-image.h"
|
||||
|
@ -34,6 +34,7 @@
|
||||
static int makefs(const char *type, const char *device) {
|
||||
const char *mkfs;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
if (streq(type, "swap"))
|
||||
mkfs = "/sbin/mkswap";
|
||||
@ -42,19 +43,14 @@ static int makefs(const char *type, const char *device) {
|
||||
if (access(mkfs, X_OK) != 0)
|
||||
return log_error_errno(errno, "%s is not executable: %m", mkfs);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "fork(): %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "fork(): %m");
|
||||
if (r == 0) {
|
||||
const char *cmdline[3] = { mkfs, device, NULL };
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
execv(cmdline[0], (char**) cmdline);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -106,21 +106,17 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = log_error_errno(errno, "fork(): %m");
|
||||
r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "fork(): %m");
|
||||
goto finish;
|
||||
}
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
execv(cmdline[0], (char**) cmdline);
|
||||
_exit(1); /* Operational error */
|
||||
_exit(EXIT_FAILURE); /* Operational error */
|
||||
}
|
||||
|
||||
r = wait_for_terminate_and_warn("quotacheck", pid, true);
|
||||
|
@ -87,19 +87,14 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
log_debug("Remounting %s", me->mnt_dir);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = log_error_errno(errno, "Failed to fork: %m");
|
||||
r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to fork: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
(void) prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
|
||||
execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount"));
|
||||
|
||||
log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "architecture.h"
|
||||
#include "ask-password-api.h"
|
||||
#include "blkid-util.h"
|
||||
#include "blockdev-util.h"
|
||||
#include "copy.h"
|
||||
#include "crypt-util.h"
|
||||
#include "def.h"
|
||||
|
@ -1278,11 +1278,10 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return -errno;
|
||||
|
||||
if (child == 0) {
|
||||
r = safe_fork("(sd-bootid)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
int fd;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
@ -123,20 +123,15 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
|
||||
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0) {
|
||||
sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (r == 0) {
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
fd = safe_close(fd);
|
||||
|
||||
execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
|
||||
|
@ -62,7 +62,7 @@ static bool stderr_redirected = false;
|
||||
int pager_open(bool no_pager, bool jump_to_end) {
|
||||
_cleanup_close_pair_ int fd[2] = { -1, -1 };
|
||||
const char *pager;
|
||||
pid_t parent_pid;
|
||||
int r;
|
||||
|
||||
if (no_pager)
|
||||
return 0;
|
||||
@ -89,18 +89,13 @@ int pager_open(bool no_pager, bool jump_to_end) {
|
||||
if (pipe2(fd, O_CLOEXEC) < 0)
|
||||
return log_error_errno(errno, "Failed to create pager pipe: %m");
|
||||
|
||||
parent_pid = getpid_cached();
|
||||
|
||||
pager_pid = fork();
|
||||
if (pager_pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork pager: %m");
|
||||
|
||||
/* In the child start the pager */
|
||||
if (pager_pid == 0) {
|
||||
r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pager_pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork pager: %m");
|
||||
if (r == 0) {
|
||||
const char* less_opts, *less_charset;
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
/* In the child start the pager */
|
||||
|
||||
(void) dup2(fd[0], STDIN_FILENO);
|
||||
safe_close_pair(fd);
|
||||
@ -124,15 +119,6 @@ int pager_open(bool no_pager, bool jump_to_end) {
|
||||
setenv("LESSCHARSET", less_charset, 1) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Make sure the pager goes away when the parent dies */
|
||||
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
/* Check whether our parent died before we were able
|
||||
* to set the death signal */
|
||||
if (getppid() != parent_pid)
|
||||
_exit(EXIT_SUCCESS);
|
||||
|
||||
if (pager) {
|
||||
execlp(pager, pager, NULL);
|
||||
execl("/bin/sh", "sh", "-c", pager, NULL);
|
||||
@ -222,24 +208,11 @@ int show_man_page(const char *desc, bool null_stdio) {
|
||||
} else
|
||||
args[1] = desc;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0), &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
if (null_stdio) {
|
||||
r = make_null_stdio();
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to kill stdio: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
execvp(args[0], (char**) args);
|
||||
log_error_errno(errno, "Failed to execute man: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
|
@ -40,8 +40,9 @@ int ask_password_agent_open(void) {
|
||||
if (!isatty(STDIN_FILENO))
|
||||
return 0;
|
||||
|
||||
r = fork_agent(&agent_pid,
|
||||
r = fork_agent("(sd-askpwagent)",
|
||||
NULL, 0,
|
||||
&agent_pid,
|
||||
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
|
||||
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
|
||||
if (r < 0)
|
||||
@ -56,8 +57,7 @@ void ask_password_agent_close(void) {
|
||||
return;
|
||||
|
||||
/* Inform agent that we are done */
|
||||
(void) kill(agent_pid, SIGTERM);
|
||||
(void) kill(agent_pid, SIGCONT);
|
||||
(void) kill_and_sigcont(agent_pid, SIGTERM);
|
||||
(void) wait_for_terminate(agent_pid, NULL);
|
||||
agent_pid = 0;
|
||||
}
|
||||
|
@ -38,9 +38,8 @@
|
||||
static pid_t agent_pid = 0;
|
||||
|
||||
int polkit_agent_open(void) {
|
||||
int r;
|
||||
int pipe_fd[2];
|
||||
char notify_fd[DECIMAL_STR_MAX(int) + 1];
|
||||
int pipe_fd[2], r;
|
||||
|
||||
if (agent_pid > 0)
|
||||
return 0;
|
||||
@ -49,8 +48,7 @@ int polkit_agent_open(void) {
|
||||
if (geteuid() == 0)
|
||||
return 0;
|
||||
|
||||
/* We check STDIN here, not STDOUT, since this is about input,
|
||||
* not output */
|
||||
/* We check STDIN here, not STDOUT, since this is about input, not output */
|
||||
if (!isatty(STDIN_FILENO))
|
||||
return 0;
|
||||
|
||||
@ -59,8 +57,9 @@ int polkit_agent_open(void) {
|
||||
|
||||
xsprintf(notify_fd, "%i", pipe_fd[1]);
|
||||
|
||||
r = fork_agent(&agent_pid,
|
||||
r = fork_agent("(polkit-agent)",
|
||||
&pipe_fd[1], 1,
|
||||
&agent_pid,
|
||||
POLKIT_AGENT_BINARY_PATH,
|
||||
POLKIT_AGENT_BINARY_PATH, "--notify-fd", notify_fd, "--fallback", NULL);
|
||||
|
||||
@ -84,9 +83,7 @@ void polkit_agent_close(void) {
|
||||
return;
|
||||
|
||||
/* Inform agent that we are done */
|
||||
(void) kill(agent_pid, SIGTERM);
|
||||
(void) kill(agent_pid, SIGCONT);
|
||||
|
||||
(void) kill_and_sigcont(agent_pid, SIGTERM);
|
||||
(void) wait_for_terminate(agent_pid, NULL);
|
||||
agent_pid = 0;
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ const char* get_testdata_dir(const char *suffix) {
|
||||
if (env) {
|
||||
if (access(env, F_OK) < 0) {
|
||||
fputs("ERROR: $SYSTEMD_TEST_DATA directory does not exist\n", stderr);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strncpy(testdir, env, sizeof(testdir) - 1);
|
||||
} else {
|
||||
@ -65,7 +65,7 @@ const char* get_testdata_dir(const char *suffix) {
|
||||
/* test this without the suffix, as it may contain a glob */
|
||||
if (access(testdir, F_OK) < 0) {
|
||||
fputs("ERROR: Cannot find testdata directory, set $SYSTEMD_TEST_DATA\n", stderr);
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,18 +81,13 @@ static int start_default_target(sd_bus *bus) {
|
||||
|
||||
static int fork_wait(const char* const cmdline[]) {
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "fork(): %m");
|
||||
if (pid == 0) {
|
||||
|
||||
r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "fork(): %m");
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
execv(cmdline[0], (char**) cmdline);
|
||||
log_error_errno(errno, "Failed to execute %s: %m", cmdline[0]);
|
||||
_exit(EXIT_FAILURE); /* Operational error */
|
||||
|
@ -3539,10 +3539,10 @@ static int load_kexec_kernel(void) {
|
||||
if (arg_dry_run)
|
||||
return 0;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
else if (pid == 0) {
|
||||
r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
|
||||
const char* const args[] = {
|
||||
KEXEC,
|
||||
@ -3552,14 +3552,10 @@ static int load_kexec_kernel(void) {
|
||||
NULL };
|
||||
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
|
||||
|
||||
execv(args[0], (char * const *) args);
|
||||
_exit(EXIT_FAILURE);
|
||||
} else
|
||||
}
|
||||
|
||||
return wait_for_terminate_and_warn("kexec", pid, true);
|
||||
}
|
||||
|
||||
@ -6123,15 +6119,11 @@ static int enable_sysv_units(const char *verb, char **args) {
|
||||
if (!arg_quiet)
|
||||
log_info("Executing: %s", l);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
else if (pid == 0) {
|
||||
j = safe_fork("(sysv)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (j < 0)
|
||||
return log_error_errno(j, "Failed to fork: %m");
|
||||
if (j == 0) {
|
||||
/* Child */
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
execv(argv[0], (char**) argv);
|
||||
log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
|
||||
_exit(EXIT_FAILURE);
|
||||
@ -7000,20 +6992,16 @@ static int run_editor(char **paths) {
|
||||
|
||||
assert(paths);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
const char **args;
|
||||
char *editor, **editor_args = NULL;
|
||||
char **tmp_path, **original_path, *p;
|
||||
unsigned n_editor_args = 0, i = 1;
|
||||
size_t argc;
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
argc = strv_length(paths)/2 + 1;
|
||||
|
||||
/* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
|
||||
|
@ -43,7 +43,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
assert_se(asynchronous_job(async_func, NULL) >= 0);
|
||||
|
||||
assert_se(asynchronous_sync() >= 0);
|
||||
assert_se(asynchronous_sync(NULL) >= 0);
|
||||
|
||||
sleep(1);
|
||||
|
||||
|
@ -80,7 +80,7 @@ static void fork_test(void (*test_func)(void)) {
|
||||
assert_se(pid >= 0);
|
||||
if (pid == 0) {
|
||||
test_func();
|
||||
exit(0);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (pid > 0) {
|
||||
int status;
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
@ -353,7 +354,7 @@ static void test_get_process_cmdline_harder(void) {
|
||||
line = mfree(line);
|
||||
|
||||
safe_close(fd);
|
||||
_exit(0);
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void test_rename_process_now(const char *p, int ret) {
|
||||
@ -462,7 +463,7 @@ static void test_getpid_cached(void) {
|
||||
c = getpid();
|
||||
|
||||
assert_se(a == b && a == c);
|
||||
_exit(0);
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
d = raw_getpid();
|
||||
@ -497,6 +498,28 @@ static void test_getpid_measure(void) {
|
||||
log_info("getpid_cached(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
|
||||
}
|
||||
|
||||
static void test_safe_fork(void) {
|
||||
siginfo_t status;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
BLOCK_SIGNALS(SIGCHLD);
|
||||
|
||||
r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_REOPEN_LOG, &pid);
|
||||
assert_se(r >= 0);
|
||||
|
||||
if (r == 0) {
|
||||
/* child */
|
||||
usleep(100 * USEC_PER_MSEC);
|
||||
|
||||
_exit(88);
|
||||
}
|
||||
|
||||
assert_se(wait_for_terminate(pid, &status) >= 0);
|
||||
assert_se(status.si_code == CLD_EXITED);
|
||||
assert_se(status.si_status == 88);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
@ -523,6 +546,7 @@ int main(int argc, char *argv[]) {
|
||||
test_rename_process();
|
||||
test_getpid_cached();
|
||||
test_getpid_measure();
|
||||
test_safe_fork();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -693,11 +693,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
* If one of the tasks does handle a password, the remaining tasks
|
||||
* will be terminated.
|
||||
*/
|
||||
static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv[]) {
|
||||
static int ask_on_this_console(const char *tty, pid_t *ret_pid, int argc, char *argv[]) {
|
||||
struct sigaction sig = {
|
||||
.sa_handler = nop_signal_handler,
|
||||
.sa_flags = SA_NOCLDSTOP | SA_RESTART,
|
||||
};
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0);
|
||||
|
||||
@ -707,18 +709,14 @@ static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv
|
||||
sig.sa_handler = SIG_DFL;
|
||||
assert_se(sigaction(SIGHUP, &sig, NULL) >= 0);
|
||||
|
||||
*pid = fork();
|
||||
if (*pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork process: %m");
|
||||
|
||||
if (*pid == 0) {
|
||||
r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork process: %m");
|
||||
if (r == 0) {
|
||||
int ac;
|
||||
|
||||
assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0);
|
||||
|
||||
reset_signal_mask();
|
||||
reset_all_signal_handlers();
|
||||
|
||||
for (ac = 0; ac < argc; ac++) {
|
||||
if (streq(argv[ac], "--console")) {
|
||||
argv[ac] = strjoina("--console=", tty);
|
||||
@ -731,6 +729,8 @@ static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv
|
||||
execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, argv);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*ret_pid = pid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "mtd_probe.h"
|
||||
|
||||
static const uint8_t cis_signature[] = {
|
||||
@ -35,16 +36,16 @@ static const uint8_t cis_signature[] = {
|
||||
};
|
||||
|
||||
|
||||
void probe_smart_media(int mtd_fd, mtd_info_t* info)
|
||||
{
|
||||
void probe_smart_media(int mtd_fd, mtd_info_t* info) {
|
||||
int sector_size;
|
||||
int block_size;
|
||||
int size_in_megs;
|
||||
int spare_count;
|
||||
char* cis_buffer = malloc(SM_SECTOR_SIZE);
|
||||
_cleanup_free_ uint8_t *cis_buffer = NULL;
|
||||
int offset;
|
||||
int cis_found = 0;
|
||||
|
||||
cis_buffer = malloc(SM_SECTOR_SIZE);
|
||||
if (!cis_buffer)
|
||||
return;
|
||||
|
||||
@ -89,9 +90,8 @@ void probe_smart_media(int mtd_fd, mtd_info_t* info)
|
||||
goto exit;
|
||||
|
||||
printf("MTD_FTL=smartmedia\n");
|
||||
free(cis_buffer);
|
||||
exit(0);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
exit:
|
||||
free(cis_buffer);
|
||||
return;
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ static int set_options(struct udev *udev,
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
exit(0);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'p':
|
||||
if (streq(optarg, "0x80"))
|
||||
@ -393,7 +393,7 @@ static int set_options(struct udev *udev,
|
||||
|
||||
case 'V':
|
||||
printf("%s\n", PACKAGE_VERSION);
|
||||
exit(0);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'x':
|
||||
export = true;
|
||||
@ -608,7 +608,7 @@ int main(int argc, char **argv)
|
||||
* Get command line options (overriding any config file settings).
|
||||
*/
|
||||
if (set_options(udev, argc, argv, maj_min_dev) < 0)
|
||||
exit(1);
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (!dev_specified) {
|
||||
log_error("No device specified.");
|
||||
|
@ -774,10 +774,12 @@ int udev_event_spawn(struct udev_event *event,
|
||||
}
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
switch(pid) {
|
||||
case 0:
|
||||
{
|
||||
err = safe_fork("(spawn)", FORK_RESET_SIGNALS, &pid);
|
||||
if (err < 0) {
|
||||
log_error_errno(err, "fork of '%s' failed: %m", cmd);
|
||||
goto out;
|
||||
}
|
||||
if (err == 0) {
|
||||
char arg[UTIL_PATH_SIZE];
|
||||
char *argv[128];
|
||||
char program[UTIL_PATH_SIZE];
|
||||
@ -802,11 +804,7 @@ int udev_event_spawn(struct udev_event *event,
|
||||
|
||||
_exit(2);
|
||||
}
|
||||
case -1:
|
||||
log_error_errno(errno, "fork of '%s' failed: %m", cmd);
|
||||
err = -1;
|
||||
goto out;
|
||||
default:
|
||||
|
||||
/* parent closed child's ends of pipes */
|
||||
outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
|
||||
errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
|
||||
@ -818,7 +816,6 @@ int udev_event_spawn(struct udev_event *event,
|
||||
result, ressize);
|
||||
|
||||
err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
|
||||
}
|
||||
|
||||
out:
|
||||
if (outpipe[READ_END] >= 0)
|
||||
|
@ -133,6 +133,7 @@ static int keyboard_load_and_wait(const char *vc, const char *map, const char *m
|
||||
const char *args[8];
|
||||
unsigned i = 0;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
/* An empty map means kernel map */
|
||||
if (isempty(map))
|
||||
@ -152,14 +153,10 @@ static int keyboard_load_and_wait(const char *vc, const char *map, const char *m
|
||||
log_debug("Executing \"%s\"...",
|
||||
strnull((cmd = strv_join((char**) args, " "))));
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
else if (pid == 0) {
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
execv(args[0], (char **) args);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -172,6 +169,7 @@ static int font_load_and_wait(const char *vc, const char *font, const char *map,
|
||||
const char *args[9];
|
||||
unsigned i = 0;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
/* Any part can be set independently */
|
||||
if (isempty(font) && isempty(map) && isempty(unimap))
|
||||
@ -195,14 +193,10 @@ static int font_load_and_wait(const char *vc, const char *font, const char *map,
|
||||
log_debug("Executing \"%s\"...",
|
||||
strnull((cmd = strv_join((char**) args, " "))));
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork: %m");
|
||||
else if (pid == 0) {
|
||||
|
||||
(void) reset_all_signal_handlers();
|
||||
(void) reset_signal_mask();
|
||||
|
||||
r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fork: %m");
|
||||
if (r == 0) {
|
||||
execv(args[0], (char **) args);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user