Commit c721d51d authored by Thomas Haller's avatar Thomas Haller
Browse files

systemd: update code from upstream (2018-01-01)

This is a direct dump from systemd git on 2017-01-01, git commit
ad552e587f21bf00013d41d48737009a20be6479.

======

SYSTEMD_DIR=../systemd
COMMIT=ad552e587f21bf00013d41d48737009a20be6479

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files :/src/systemd/src/ \
             :/shared/nm-utils/siphash24.c \
             :/shared/nm-utils/siphash24.h \
             :/shared/nm-utils/unaligned.h | \
  xargs -d '\n' rm -f

nm_copy_sd() {
    mkdir -p "./src/systemd/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}

nm_copy_sd_shared() {
    mkdir -p "./shared/nm-utils/"
    cp "$SYSTEMD_DIR/$1" "./shared/nm-utils/${1##*/}"
}

nm_copy_sd "src/basic/alloc-util.c"
nm_copy_sd "src/basic/alloc-util.h"
nm_copy_sd "src/basic/async.h"
nm_copy_sd "src/basic/escape.c"
nm_copy_sd "src/basic/escape.h"
nm_copy_sd "src/basic/ether-addr-util.c"
nm_copy_sd "src/basic/ether-addr-util.h"
nm_copy_sd "src/basic/extract-word.c"
nm_copy_sd "src/basic/extract-word.h"
nm_copy_sd "src/basic/fileio.c"
nm_copy_sd "src/basic/fileio.h"
nm_copy_sd "src/basic/fd-util.c"
nm_copy_sd "src/basic/fd-util.h"
nm_copy_sd "src/basic/fs-util.c"
nm_copy_sd "src/basic/fs-util.h"
nm_copy_sd "src/basic/hash-funcs.c"
nm_copy_sd "src/basic/hash-funcs.h"
nm_copy_sd "src/basic/hashmap.c"
nm_copy_sd "src/basic/hashmap.h"
nm_copy_sd "src/basic/hexdecoct.c"
nm_copy_sd "src/basic/hexdecoct.h"
nm_copy_sd "src/basic/hostname-util.c"
nm_copy_sd "src/basic/hostname-util.h"
nm_copy_sd "src/basic/in-addr-util.c"
nm_copy_sd "src/basic/in-addr-util.h"
nm_copy_sd "src/basic/io-util.c"
nm_copy_sd "src/basic/io-util.h"
nm_copy_sd "src/basic/list.h"
nm_copy_sd "src/basic/log.h"
nm_copy_sd "src/basic/macro.h"
nm_copy_sd "src/basic/mempool.h"
nm_copy_sd "src/basic/mempool.c"
nm_copy_sd "src/basic/parse-util.c"
nm_copy_sd "src/basic/parse-util.h"
nm_copy_sd "src/basic/path-util.c"
nm_copy_sd "src/basic/path-util.h"
nm_copy_sd "src/basic/prioq.h"
nm_copy_sd "src/basic/prioq.c"
nm_copy_sd "src/basic/process-util.h"
nm_copy_sd "src/basic/process-util.c"
nm_copy_sd "src/basic/random-util.c"
nm_copy_sd "src/basic/random-util.h"
nm_copy_sd "src/basic/refcnt.h"
nm_copy_sd "src/basic/set.h"
nm_copy_sd "src/basic/signal-util.h"
nm_copy_sd_shared "src/basic/siphash24.c"
nm_copy_sd_shared "src/basic/siphash24.h"
nm_copy_sd "src/basic/socket-util.c"
nm_copy_sd "src/basic/socket-util.h"
nm_copy_sd "src/basic/sparse-endian.h"
nm_copy_sd "src/basic/stdio-util.h"
nm_copy_sd "src/basic/string-table.c"
nm_copy_sd "src/basic/string-table.h"
nm_copy_sd "src/basic/string-util.c"
nm_copy_sd "src/basic/string-util.h"
nm_copy_sd "src/basic/strv.c"
nm_copy_sd "src/basic/strv.h"
nm_copy_sd "src/basic/time-util.c"
nm_copy_sd "src/basic/time-util.h"
nm_copy_sd "src/basic/umask-util.h"
nm_copy_sd_shared "src/basic/unaligned.h"
nm_copy_sd "src/basic/utf8.c"
nm_copy_sd "src/basic/utf8.h"
nm_copy_sd "src/basic/util.c"
nm_copy_sd "src/basic/util.h"
nm_copy_sd "src/libsystemd-network/arp-util.c"
nm_copy_sd "src/libsystemd-network/arp-util.h"
nm_copy_sd "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-network.c"
nm_copy_sd "src/libsystemd-network/dhcp-option.c"
nm_copy_sd "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd "src/libsystemd-network/lldp-internal.h"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.c"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.h"
nm_copy_sd "src/libsystemd-network/lldp-network.c"
nm_copy_sd "src/libsystemd-network/lldp-network.h"
nm_copy_sd "src/libsystemd-network/network-internal.c"
nm_copy_sd "src/libsystemd-network/network-internal.h"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4acd.c"
nm_copy_sd "src/libsystemd-network/sd-lldp.c"
nm_copy_sd "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd "src/shared/dns-domain.c"
nm_copy_sd "src/shared/dns-domain.h"
nm_copy_sd "src/systemd/_sd-common.h"
nm_copy_sd "src/systemd/sd-dhcp6-client.h"
nm_copy_sd "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd "src/systemd/sd-dhcp-client.h"
nm_copy_sd "src/systemd/sd-dhcp-lease.h"
nm_copy_sd "src/systemd/sd-event.h"
nm_copy_sd "src/systemd/sd-ndisc.h"
nm_copy_sd "src/systemd/sd-id128.h"
nm_copy_sd "src/systemd/sd-ipv4acd.h"
nm_copy_sd "src/systemd/sd-ipv4ll.h"
nm_copy_sd "src/systemd/sd-lldp.h"
parent 60afcc36
......@@ -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);
......@@ -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;
......@@ -427,7 +426,7 @@ int move_fd(int from, int to, int cloexec) {
int acquire_data_fd(const void *data, size_t size, unsigned flags) {
char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_close_pair_ int pipefds[2] = { -1, -1 };
char pattern[] = "/dev/shm/data-fd-XXXXXX";
_cleanup_close_ int fd = -1;
......
......@@ -23,6 +23,7 @@
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
......@@ -64,9 +65,15 @@ int write_string_stream_ts(
assert(f);
assert(line);
fputs(line, f);
if (ferror(f))
return -EIO;
if (fputs(line, f) == EOF)
return -errno;
if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"))
fputc('\n', f);
if (fputc('\n', f) == EOF)
return -errno;
if (ts) {
struct timespec twice[2] = {*ts, *ts};
......@@ -98,6 +105,7 @@ static int write_string_file_atomic(
if (r < 0)
return r;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
(void) fchmod_umask(fileno(f), 0644);
r = write_string_stream_ts(f, line, flags, ts);
......@@ -167,6 +175,8 @@ int write_string_file_ts(
}
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
setvbuf(f, NULL, _IONBF, 0);
......@@ -203,6 +213,8 @@ int read_one_line_file(const char *fn, char **line) {
if (!f)
return -errno;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
r = read_line(f, LONG_LINE_MAX, line);
return r < 0 ? r : 0;
}
......@@ -228,6 +240,8 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
if (!f)
return -errno;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
/* We try to read one byte more than we need, so that we know whether we hit eof */
errno = 0;
k = fread(buf, 1, l + accept_extra_nl + 1, f);
......@@ -323,6 +337,8 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
if (!f)
return -errno;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
return read_full_stream(f, contents, size);
}
......@@ -879,7 +895,8 @@ int write_env_file(const char *fname, char **l) {
if (r < 0)
return r;
fchmod_umask(fileno(f), 0644);
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
(void) fchmod_umask(fileno(f), 0644);
STRV_FOREACH(i, l)
write_env_var(f, *i);
......@@ -1461,7 +1478,7 @@ int link_tmpfile(int fd, const char *path, const char *target) {
if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
return -errno;
} else {
char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
......
......@@ -580,7 +580,7 @@ int tmp_dir(const char **ret) {
}
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
int r;
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
......@@ -825,7 +825,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
}
int access_fd(int fd, int mode) {
char p[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
int r;
/* Like access() but operates on an already open fd */
......
......@@ -335,3 +335,5 @@ int log_syntax_internal(
"String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
} \
})
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
......@@ -26,6 +26,7 @@
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
......@@ -55,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"
......@@ -130,6 +132,8 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
return -errno;
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
if (max_length == 1) {
/* If there's only room for one byte, return the empty string */
......@@ -293,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;
......@@ -406,6 +417,8 @@ int is_kernel_thread(pid_t pid) {
return -errno;
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
count = fread(&c, 1, 1, f);
eof = feof(f);
fclose(f);
......@@ -487,6 +500,8 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
return -errno;
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
FOREACH_LINE(line, f, return -errno) {
char *l;
......@@ -565,6 +580,8 @@ int get_process_environ(pid_t pid, char **env) {
return -errno;
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
while ((c = fgetc(f)) != EOF) {
if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
return -ENOMEM;
......@@ -699,6 +716,67 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
return -EPROTO;
}
/*
* Return values:
* < 0 : wait_for_terminate_with_timeout() failed to get the state of the
* process, the process timed out, the process was terminated by a
* signal, or failed for an unknown reason.
* >=0 : The process terminated normally with no failures.
*
* Success is indicated by a return value of zero, a timeout is indicated
* by ETIMEDOUT, and all other child failure states are indicated by error
* is indicated by a non-zero value.
*/
int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
sigset_t mask;
int r;
usec_t until;
assert_se(sigemptyset(&mask) == 0);
assert_se(sigaddset(&mask, SIGCHLD) == 0);
/* Drop into a sigtimewait-based timeout. Waiting for the
* pid to exit. */
until = now(CLOCK_MONOTONIC) + timeout;
for (;;) {
usec_t n;
siginfo_t status = {};
struct timespec ts;
n = now(CLOCK_MONOTONIC);
if (n >= until)
break;
r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0;
/* Assuming we woke due to the child exiting. */
if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
if (status.si_pid == pid) {
/* This is the correct child.*/
if (status.si_code == CLD_EXITED)
return (status.si_status == 0) ? 0 : -EPROTO;
else
return -EPROTO;
}
}
/* Not the child, check for errors and proceed appropriately */
if (r < 0) {
switch (r) {
case -EAGAIN:
/* Timed out, child is likely hung. */
return -ETIMEDOUT;
case -EINTR:
/* Received a different signal and should retry */
continue;
default:
/* Return any unexpected errors */
return r;
}
}
}
return -EPROTO;
}
void sigkill_wait(pid_t pid) {
assert(pid > 1);
......@@ -749,6 +827,8 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
return -errno;
}
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
l = strlen(field);
r = 0;
......@@ -1062,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",
......
......@@ -33,6 +33,7 @@
#include "format-util.h"
#include "ioprio.h"
#include "macro.h"
#include "time-util.h"
#define procfs_file_alloca(pid, field) \
({ \
......@@ -41,7 +42,7 @@
if (_pid_ == 0) { \
_r_ = ("/proc/self/" field); \
} else { \
_r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
_r_ = alloca(STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
} \
_r_; \
......@@ -61,6 +62,7 @@ int get_process_ppid(pid_t pid, pid_t *ppid);
int wait_for_terminate(pid_t pid, siginfo_t *status);
int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout);
void sigkill_wait(pid_t pid);
void sigkill_waitp(pid_t *pid);
......@@ -140,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, ...);
......@@ -55,6 +55,17 @@
# define IDN_FLAGS 0
#endif
static const char* const socket_address_type_table[] = {
[SOCK_STREAM] = "Stream",
[SOCK_DGRAM] = "Datagram",
[SOCK_RAW] = "Raw",
[SOCK_RDM] = "ReliableDatagram",
[SOCK_SEQPACKET] = "SequentialPacket",
[SOCK_DCCP] = "DatagramCongestionControl",
};
DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
unsigned u;
......@@ -122,7 +133,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
} else if (startswith(s, "vsock:")) {
/* AF_VSOCK socket in vsock:cid:port notation */