From 14098cbc0750ad591a8dbfc3944b258bfb62c2ba Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 4 Apr 2018 11:52:14 +0200 Subject: [PATCH] systemd: update code from upstream (2018-04-04) This is a direct dump from systemd git. ====== SYSTEMD_DIR=../systemd COMMIT=c0f9017c1195b9bc3743e8dd000a18d3898b0034 ( 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" --- src/systemd/src/basic/alloc-util.h | 13 +- src/systemd/src/basic/extract-word.c | 3 +- src/systemd/src/basic/fd-util.c | 173 +++++++++++++++--- src/systemd/src/basic/fd-util.h | 24 ++- src/systemd/src/basic/fileio.c | 81 +++----- src/systemd/src/basic/fs-util.c | 150 ++++++++++++--- src/systemd/src/basic/fs-util.h | 5 + src/systemd/src/basic/hexdecoct.c | 2 +- src/systemd/src/basic/log.h | 17 +- src/systemd/src/basic/macro.h | 33 ++-- src/systemd/src/basic/parse-util.c | 37 +--- src/systemd/src/basic/parse-util.h | 20 +- src/systemd/src/basic/path-util.c | 3 +- src/systemd/src/basic/path-util.h | 10 +- src/systemd/src/basic/prioq.c | 2 +- src/systemd/src/basic/process-util.c | 27 ++- src/systemd/src/basic/process-util.h | 2 +- src/systemd/src/basic/socket-util.c | 3 +- src/systemd/src/basic/stdio-util.h | 6 +- src/systemd/src/basic/string-table.h | 9 +- src/systemd/src/basic/strv.c | 16 +- src/systemd/src/basic/util.c | 4 +- src/systemd/src/basic/util.h | 13 ++ src/systemd/src/libsystemd-network/arp-util.c | 5 +- .../src/libsystemd-network/dhcp-network.c | 10 +- .../src/libsystemd-network/dhcp-option.c | 6 +- .../src/libsystemd-network/dhcp6-network.c | 4 +- .../src/libsystemd-network/dhcp6-option.c | 3 +- .../src/libsystemd-network/lldp-network.c | 5 +- .../src/libsystemd-network/network-internal.c | 20 +- .../src/libsystemd-network/sd-dhcp-client.c | 42 +++-- .../src/libsystemd-network/sd-dhcp-lease.c | 3 +- src/systemd/src/shared/dns-domain.c | 6 +- src/systemd/src/systemd/sd-dhcp-client.h | 5 + 34 files changed, 501 insertions(+), 261 deletions(-) diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h index 02dee37d3..b1e0edbb7 100644 --- a/src/systemd/src/basic/alloc-util.h +++ b/src/systemd/src/basic/alloc-util.h @@ -74,12 +74,14 @@ _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t return malloc(size * need); } -_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) { +#if !HAVE_REALLOCARRAY +_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { if (size_multiply_overflow(size, need)) return NULL; return realloc(p, size * need); } +#endif _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { if (size_multiply_overflow(size, need)) @@ -128,3 +130,12 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); _new_ = alloca_align(_size_, (align)); \ (void*)memset(_new_, 0, _size_); \ }) + +/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to + * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ +#define TAKE_PTR(ptr) \ + ({ \ + typeof(ptr) _ptr_ = (ptr); \ + (ptr) = NULL; \ + _ptr_; \ + }) diff --git a/src/systemd/src/basic/extract-word.c b/src/systemd/src/basic/extract-word.c index 5e4256048..7a6b56f07 100644 --- a/src/systemd/src/basic/extract-word.c +++ b/src/systemd/src/basic/extract-word.c @@ -194,8 +194,7 @@ finish: finish_force_next: s[sz] = 0; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return 1; } diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index 61a93fcb4..8bb8c9a62 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -191,12 +191,6 @@ int fd_cloexec(int fd, bool cloexec) { return 0; } -void stdio_unset_cloexec(void) { - (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) { unsigned i; @@ -367,14 +361,21 @@ bool fdname_is_valid(const char *s) { } int fd_get_path(int fd, char **ret) { - char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int dir = -1; + char fdname[DECIMAL_STR_MAX(int)]; int r; - xsprintf(procfs_path, "/proc/self/fd/%i", fd); + dir = open("/proc/self/fd/", O_CLOEXEC | O_DIRECTORY | O_PATH); + if (dir < 0) + /* /proc is not available or not set up properly, we're most likely + * in some chroot environment. */ + return errno == ENOENT ? -EOPNOTSUPP : -errno; - r = readlink_malloc(procfs_path, ret); + xsprintf(fdname, "%i", fd); - if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */ + r = readlinkat_malloc(dir, fdname, ret); + if (r == -ENOENT) + /* If the file doesn't exist the fd is invalid */ return -EBADF; return r; @@ -426,7 +427,6 @@ 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)]; _cleanup_close_pair_ int pipefds[2] = { -1, -1 }; char pattern[] = "/dev/shm/data-fd-XXXXXX"; _cleanup_close_ int fd = -1; @@ -483,10 +483,7 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags) { if (r < 0) return r; - r = fd; - fd = -1; - - return r; + return TAKE_FD(fd); } try_pipe: @@ -523,10 +520,7 @@ try_pipe: (void) fd_nonblock(pipefds[0], false); - r = pipefds[0]; - pipefds[0] = -1; - - return r; + return TAKE_FD(pipefds[0]); } try_dev_shm: @@ -542,12 +536,7 @@ try_dev_shm: return -EIO; /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ - xsprintf(procfs_path, "/proc/self/fd/%i", fd); - r = open(procfs_path, O_RDONLY|O_CLOEXEC); - if (r < 0) - return -errno; - - return r; + return fd_reopen(fd, O_RDONLY|O_CLOEXEC); } try_dev_shm_without_o_tmpfile: @@ -615,3 +604,137 @@ int fd_move_above_stdio(int fd) { (void) close(fd); return copy; } + +int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) { + + int fd[3] = { /* Put together an array of fds we work on */ + original_input_fd, + original_output_fd, + original_error_fd + }; + + int r, i, + null_fd = -1, /* if we open /dev/null, we store the fd to it here */ + copy_fd[3] = { -1, -1, -1 }; /* This contains all fds we duplicate here temporarily, and hence need to close at the end */ + bool null_readable, null_writable; + + /* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors is + * specified as -1 it will be connected with /dev/null instead. If any of the file descriptors is passed as + * itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is turned off should it be + * on. + * + * Note that if any of the passed file descriptors are > 2 they will be closed — both on success and on + * failure! Thus, callers should assume that when this function returns the input fds are invalidated. + * + * Note that when this function fails stdin/stdout/stderr might remain half set up! + * + * O_CLOEXEC is turned off for all three file descriptors (which is how it should be for + * stdin/stdout/stderr). */ + + null_readable = original_input_fd < 0; + null_writable = original_output_fd < 0 || original_error_fd < 0; + + /* First step, open /dev/null once, if we need it */ + if (null_readable || null_writable) { + + /* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */ + null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR : + null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC); + if (null_fd < 0) { + r = -errno; + goto finish; + } + + /* If this fd is in the 0…2 range, let's move it out of it */ + if (null_fd < 3) { + int copy; + + copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */ + if (copy < 0) { + r = -errno; + goto finish; + } + + safe_close(null_fd); + null_fd = copy; + } + } + + /* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */ + for (i = 0; i < 3; i++) { + + if (fd[i] < 0) + fd[i] = null_fd; /* A negative parameter means: connect this one to /dev/null */ + else if (fd[i] != i && fd[i] < 3) { + /* This fd is in the 0…2 territory, but not at its intended place, move it out of there, so that we can work there. */ + copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */ + if (copy_fd[i] < 0) { + r = -errno; + goto finish; + } + + fd[i] = copy_fd[i]; + } + } + + /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that we + * have freedom to move them around. If the fds already were at the right places then the specific fds are + * -1. Let's now move them to the right places. This is the point of no return. */ + for (i = 0; i < 3; i++) { + + if (fd[i] == i) { + + /* fd is already in place, but let's make sure O_CLOEXEC is off */ + r = fd_cloexec(i, false); + if (r < 0) + goto finish; + + } else { + assert(fd[i] > 2); + + if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */ + r = -errno; + goto finish; + } + } + } + + r = 0; + +finish: + /* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same + * fd passed in multiple times. */ + safe_close_above_stdio(original_input_fd); + if (original_output_fd != original_input_fd) + safe_close_above_stdio(original_output_fd); + if (original_error_fd != original_input_fd && original_error_fd != original_output_fd) + safe_close_above_stdio(original_error_fd); + + /* Close the copies we moved > 2 */ + for (i = 0; i < 3; i++) + safe_close(copy_fd[i]); + + /* Close our null fd, if it's > 2 */ + safe_close_above_stdio(null_fd); + + return r; +} + +int fd_reopen(int fd, int flags) { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + int new_fd; + + /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to + * turn O_RDWR fds into O_RDONLY fds. + * + * This doesn't work on sockets (since they cannot be open()ed, ever). + * + * This implicitly resets the file read index to 0. */ + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + new_fd = open(procfs_path, flags); + if (new_fd < 0) + return -errno; + + return new_fd; +} diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index 284856ae6..163b096b1 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -35,6 +35,13 @@ int close_nointr(int fd); int safe_close(int fd); void safe_close_pair(int p[]); +static inline int safe_close_above_stdio(int fd) { + if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -1 */ + return -1; + + return safe_close(fd); +} + void close_many(const int fds[], unsigned n_fd); int fclose_nointr(FILE *f); @@ -64,7 +71,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); -void stdio_unset_cloexec(void); int close_all_fds(const int except[], unsigned n_except); @@ -93,3 +99,19 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags); IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) int fd_move_above_stdio(int fd); + +int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd); + +static inline int make_null_stdio(void) { + return rearrange_stdio(-1, -1, -1); +} + +/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */ +#define TAKE_FD(fd) \ + ({ \ + int _fd_ = (fd); \ + (fd) = -1; \ + _fd_; \ + }) + +int fd_reopen(int fd, int flags); diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index 29b941348..f807842c3 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -330,8 +330,7 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { } buf[l] = 0; - *contents = buf; - buf = NULL; /* do not free */ + *contents = TAKE_PTR(buf); if (size) *size = l; @@ -363,11 +362,11 @@ static int parse_env_file_internal( void *userdata, int *n_pushed) { - _cleanup_free_ char *contents = NULL, *key = NULL; size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; - char *p, *value = NULL; - int r; + _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL; unsigned line = 1; + char *p; + int r; enum { PRE_KEY, @@ -404,10 +403,8 @@ static int parse_env_file_internal( state = KEY; last_key_whitespace = (size_t) -1; - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) + return -ENOMEM; key[n_key++] = c; } @@ -427,10 +424,8 @@ static int parse_env_file_internal( else if (last_key_whitespace == (size_t) -1) last_key_whitespace = n_key; - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) + return -ENOMEM; key[n_key++] = c; } @@ -452,7 +447,7 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - goto fail; + return r; n_key = 0; value = NULL; @@ -467,10 +462,8 @@ static int parse_env_file_internal( else if (!strchr(WHITESPACE, c)) { state = VALUE; - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -497,7 +490,7 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - goto fail; + return r; n_key = 0; value = NULL; @@ -512,10 +505,8 @@ static int parse_env_file_internal( else if (last_value_whitespace == (size_t) -1) last_value_whitespace = n_value; - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -527,10 +518,8 @@ static int parse_env_file_internal( if (!strchr(newline, c)) { /* Escaped newlines we eat up entirely */ - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -542,10 +531,8 @@ static int parse_env_file_internal( else if (c == '\\') state = SINGLE_QUOTE_VALUE_ESCAPE; else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -556,10 +543,8 @@ static int parse_env_file_internal( state = SINGLE_QUOTE_VALUE; if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -571,10 +556,8 @@ static int parse_env_file_internal( else if (c == '\\') state = DOUBLE_QUOTE_VALUE_ESCAPE; else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -585,10 +568,8 @@ static int parse_env_file_internal( state = DOUBLE_QUOTE_VALUE; if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) + return -ENOMEM; value[n_value++] = c; } @@ -633,14 +614,12 @@ static int parse_env_file_internal( r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) - goto fail; + return r; + + value = NULL; } return 0; - -fail: - free(value); - return r; } static int check_utf8ness_and_warn( @@ -1452,8 +1431,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { if (fd < 0) return -errno; - *ret_path = tmp; - tmp = NULL; + *ret_path = TAKE_PTR(tmp); return fd; } @@ -1539,8 +1517,7 @@ int read_nul_string(FILE *f, char **ret) { return -ENOMEM; } - *ret = x; - x = NULL; + *ret = TAKE_PTR(x); return 0; } diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index 85c8070a1..112aedd02 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -458,10 +458,8 @@ int get_files_in_directory(const char *path, char ***list) { n++; } - if (list) { - *list = l; - l = NULL; /* avoid freeing */ - } + if (list) + *list = TAKE_PTR(l); return n; } @@ -579,6 +577,10 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { return r; } +static bool noop_root(const char *root) { + return isempty(root) || path_equal(root, "/"); +} + static bool safe_transition(const struct stat *a, const struct stat *b) { /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files @@ -629,9 +631,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * specified path. */ /* A root directory of "/" or "" is identical to none */ - if (isempty(original_root) || path_equal(original_root, "/")) + if (noop_root(original_root)) original_root = NULL; + if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN)) == CHASE_OPEN) { + /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set + * and doesn't care about any of the other special features we provide either. */ + r = open(path, O_PATH|O_CLOEXEC); + if (r < 0) + return -errno; + + return r; + } + if (original_root) { r = path_make_absolute_cwd(original_root, &root); if (r < 0) @@ -685,8 +697,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* Just a single slash? Then we reached the end. */ if (path_equal(first, "/")) { /* Preserve the trailing slash */ - if (!strextend(&done, "/", NULL)) - return -ENOMEM; + + if (flags & CHASE_TRAIL_SLASH) + if (!strextend(&done, "/", NULL)) + return -ENOMEM; break; } @@ -732,8 +746,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, } safe_close(fd); - fd = fd_parent; - fd_parent = -1; + fd = TAKE_FD(fd_parent); continue; } @@ -838,10 +851,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, } /* If this is not a symlink, then let's just add the name we read to what we already verified. */ - if (!done) { - done = first; - first = NULL; - } else { + if (!done) + done = TAKE_PTR(first); + else { /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ if (streq(done, "/")) *done = '\0'; @@ -852,8 +864,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* And iterate again, but go one directory further down. */ safe_close(fd); - fd = child; - child = -1; + fd = TAKE_FD(child); } if (!done) { @@ -863,27 +874,100 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - if (ret) { - *ret = done; - done = NULL; - } + if (ret) + *ret = TAKE_PTR(done); if (flags & CHASE_OPEN) { - int q; - /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by * opening /proc/self/fd/xyz. */ assert(fd >= 0); - q = fd; - fd = -1; - - return q; + return TAKE_FD(fd); } return exists; } +int chase_symlinks_and_open( + const char *path, + const char *root, + unsigned chase_flags, + int open_flags, + char **ret_path) { + + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + int r; + + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + r = open(path, open_flags); + if (r < 0) + return -errno; + + return r; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + r = fd_reopen(path_fd, open_flags); + if (r < 0) + return r; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + return r; +} + +int chase_symlinks_and_opendir( + const char *path, + const char *root, + unsigned chase_flags, + char **ret_path, + DIR **ret_dir) { + + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + DIR *d; + + if (!ret_dir) + return -EINVAL; + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + d = opendir(path); + if (!d) + return -errno; + + *ret_dir = d; + return 0; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + xsprintf(procfs_path, "/proc/self/fd/%i", path_fd); + d = opendir(procfs_path); + if (!d) + return -errno; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + *ret_dir = d; + return 0; +} + int access_fd(int fd, int mode) { char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; int r; @@ -891,10 +975,9 @@ int access_fd(int fd, int mode) { /* Like access() but operates on an already open fd */ xsprintf(p, "/proc/self/fd/%i", fd); - r = access(p, mode); if (r < 0) - r = -errno; + return -errno; return r; } @@ -978,8 +1061,19 @@ int fsync_directory_of_file(int fd) { return r; r = fd_get_path(fd, &path); - if (r < 0) + if (r < 0) { + log_debug("Failed to query /proc/self/fd/%d%s: %m", + fd, + r == -EOPNOTSUPP ? ", ignoring" : ""); + + if (r == -EOPNOTSUPP) + /* If /proc is not available, we're most likely running in some + * chroot environment, and syncing the directory is not very + * important in that case. Let's just silently do nothing. */ + return 0; + return r; + } if (!path_is_absolute(path)) return -EINVAL; diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 82d7e765b..2225b7e74 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -20,6 +20,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -86,10 +87,14 @@ enum { CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */ CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */ + CHASE_TRAIL_SLASH = 1U << 5, /* If set, any trailing slash will be preserved */ }; int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); +int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path); +int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir); + /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ static inline void rmdir_and_free(char *p) { PROTECT_ERRNO; diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c index fe7e4954e..0764521b6 100644 --- a/src/systemd/src/basic/hexdecoct.c +++ b/src/systemd/src/basic/hexdecoct.c @@ -583,7 +583,7 @@ static int base64_append_width( if (len <= 0) return len; - lines = (len + width - 1) / width; + lines = DIV_ROUND_UP(len, width); slen = strlen_ptr(sep); t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines); diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h index 5b5a25bd6..314be128a 100644 --- a/src/systemd/src/basic/log.h +++ b/src/systemd/src/basic/log.h @@ -144,19 +144,6 @@ int log_object_internal( const char *extra, const char *format, ...) _printf_(10,11); -int log_object_internalv( - int level, - int error, - const char *file, - int line, - const char *func, - const char *object_field, - const char *object, - const char *extra_field, - const char *extra, - const char *format, - va_list ap) _printf_(10,0); - int log_struct_internal( int level, int error, @@ -199,7 +186,7 @@ int log_dump_internal( char *buffer); /* Logging for various assertions */ -noreturn void log_assert_failed_realm( +_noreturn_ void log_assert_failed_realm( LogRealm realm, const char *text, const char *file, @@ -208,7 +195,7 @@ noreturn void log_assert_failed_realm( #define log_assert_failed(text, ...) \ log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__) -noreturn void log_assert_failed_unreachable_realm( +_noreturn_ void log_assert_failed_unreachable_realm( LogRealm realm, const char *text, const char *file, diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index 89bdd852a..8e61ff068 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -53,6 +53,26 @@ #else #define _fallthrough_ #endif +/* Define C11 noreturn without and even on older gcc + * compiler versions */ +#ifndef _noreturn_ +#if __STDC_VERSION__ >= 201112L +#define _noreturn_ _Noreturn +#else +#define _noreturn_ __attribute__((noreturn)) +#endif +#endif + +#if !defined(HAS_FEATURE_MEMORY_SANITIZER) +# if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# define HAS_FEATURE_MEMORY_SANITIZER 1 +# endif +# endif +# if !defined(HAS_FEATURE_MEMORY_SANITIZER) +# define HAS_FEATURE_MEMORY_SANITIZER 0 +# endif +#endif /* Temporarily disable some warnings */ #define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ @@ -414,21 +434,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #endif #endif -/* Define C11 noreturn without and even on older gcc - * compiler versions */ -#ifndef noreturn -#if __STDC_VERSION__ >= 201112L -#define noreturn _Noreturn -#else -#define noreturn __attribute__((noreturn)) -#endif -#endif - #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ func(*p); \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ + } #include "log.h" diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index fa5b4a353..eacd5ba36 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -324,8 +324,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) { return -EINVAL; *error = e; - *name = n; - n = NULL; + *name = TAKE_PTR(n); return 0; } @@ -371,12 +370,13 @@ finish: } -int safe_atou(const char *s, unsigned *ret_u) { +int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) { char *x = NULL; unsigned long l; assert(s); assert(ret_u); + assert(base <= 16); /* strtoul() is happy to parse negative values, and silently * converts them to unsigned values without generating an @@ -389,7 +389,7 @@ int safe_atou(const char *s, unsigned *ret_u) { s += strspn(s, WHITESPACE); errno = 0; - l = strtoul(s, &x, 0); + l = strtoul(s, &x, base); if (errno > 0) return -errno; if (!x || x == s || *x != 0) @@ -487,17 +487,18 @@ int safe_atou8(const char *s, uint8_t *ret) { return 0; } -int safe_atou16(const char *s, uint16_t *ret) { +int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) { char *x = NULL; unsigned long l; assert(s); assert(ret); + assert(base <= 16); s += strspn(s, WHITESPACE); errno = 0; - l = strtoul(s, &x, 0); + l = strtoul(s, &x, base); if (errno > 0) return -errno; if (!x || x == s || *x != 0) @@ -531,30 +532,6 @@ int safe_atoi16(const char *s, int16_t *ret) { return 0; } -int safe_atoux16(const char *s, uint16_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - s += strspn(s, WHITESPACE); - - errno = 0; - l = strtoul(s, &x, 16); - if (errno > 0) - return -errno; - if (!x || x == s || *x != 0) - return -EINVAL; - if (s[0] == '-') - return -ERANGE; - if ((unsigned long) (uint16_t) l != l) - return -ERANGE; - - *ret = (uint16_t) l; - return 0; -} - int safe_atod(const char *s, double *ret_d) { _cleanup_(freelocalep) locale_t loc = (locale_t) 0; char *x = NULL; diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 727422056..1605cc4ff 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -44,17 +44,29 @@ int parse_syscall_and_errno(const char *in, char **name, int *error); #define FORMAT_BYTES_MAX 8 char *format_bytes(char *buf, size_t l, uint64_t t); -int safe_atou(const char *s, unsigned *ret_u); +int safe_atou_full(const char *s, unsigned base, unsigned *ret_u); + +static inline int safe_atou(const char *s, unsigned *ret_u) { + return safe_atou_full(s, 0, ret_u); +} + int safe_atoi(const char *s, int *ret_i); int safe_atollu(const char *s, unsigned long long *ret_u); int safe_atolli(const char *s, long long int *ret_i); int safe_atou8(const char *s, uint8_t *ret); -int safe_atou16(const char *s, uint16_t *ret); -int safe_atoi16(const char *s, int16_t *ret); +int safe_atou16_full(const char *s, unsigned base, uint16_t *ret); -int safe_atoux16(const char *s, uint16_t *ret); +static inline int safe_atou16(const char *s, uint16_t *ret) { + return safe_atou16_full(s, 0, ret); +} + +static inline int safe_atoux16(const char *s, uint16_t *ret) { + return safe_atou16_full(s, 16, ret); +} + +int safe_atoi16(const char *s, int16_t *ret); static inline int safe_atou32(const char *s, uint32_t *ret_u) { assert_cc(sizeof(uint32_t) == sizeof(unsigned)); diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index df9462938..d4c4a02cb 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -290,8 +290,7 @@ char **path_strv_resolve(char **l, const char *root) { r = chase_symlinks(t, root, 0, &u); if (r == -ENOENT) { if (root) { - u = orig; - orig = NULL; + u = TAKE_PTR(orig); free(t); } else u = t; diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index 89c285e07..73f1769fd 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -28,8 +28,14 @@ #include "string-util.h" #include "time-util.h" -#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" -#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" +#if HAVE_SPLIT_BIN +# define PATH_SBIN_BIN(x) x "sbin:" x "bin" +#else +# define PATH_SBIN_BIN(x) x "bin" +#endif + +#define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/") +#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/") #if HAVE_SPLIT_USR # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR diff --git a/src/systemd/src/basic/prioq.c b/src/systemd/src/basic/prioq.c index 407b17e9b..2a1f1af87 100644 --- a/src/systemd/src/basic/prioq.c +++ b/src/systemd/src/basic/prioq.c @@ -173,7 +173,7 @@ int prioq_put(Prioq *q, void *data, unsigned *idx) { struct prioq_item *j; n = MAX((q->n_items+1) * 2, 16u); - j = realloc(q->items, sizeof(struct prioq_item) * n); + j = reallocarray(q->items, n, sizeof(struct prioq_item)); if (!j) return -ENOMEM; diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c index aa41b3b68..2583b310a 100644 --- a/src/systemd/src/basic/process-util.c +++ b/src/systemd/src/basic/process-util.c @@ -623,8 +623,7 @@ int get_process_environ(pid_t pid, char **env) { } else outcome[sz] = '\0'; - *env = outcome; - outcome = NULL; + *env = TAKE_PTR(outcome); return 0; } @@ -987,7 +986,7 @@ bool is_main_thread(void) { return cached > 0; } -noreturn void freeze(void) { +_noreturn_ void freeze(void) { log_close(); @@ -1166,6 +1165,7 @@ extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void extern void* __dso_handle __attribute__ ((__weak__)); pid_t getpid_cached(void) { + static bool installed = false; pid_t current_value; /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a @@ -1186,10 +1186,18 @@ pid_t getpid_cached(void) { new_pid = raw_getpid(); - if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) { - /* OOM? Let's try again later */ - cached_pid = CACHED_PID_UNSET; - return new_pid; + if (!installed) { + /* __register_atfork() either returns 0 or -ENOMEM, in its glibc implementation. Since it's + * only half-documented (glibc doesn't document it but LSB does — though only superficially) + * we'll check for errors only in the most generic fashion possible. */ + + if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) { + /* OOM? Let's try again later */ + cached_pid = CACHED_PID_UNSET; + return new_pid; + } + + installed = true; } cached_pid = new_pid; @@ -1428,8 +1436,7 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r _exit(EXIT_FAILURE); } - if (fd > STDERR_FILENO) - close(fd); + safe_close_above_stdio(fd); } /* Count arguments */ @@ -1458,7 +1465,7 @@ static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_IDLE] = "idle" }; -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES); static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h index 93029e36e..5170adec7 100644 --- a/src/systemd/src/basic/process-util.h +++ b/src/systemd/src/basic/process-util.h @@ -91,7 +91,7 @@ int pid_from_same_root_fs(pid_t pid); bool is_main_thread(void); -noreturn void freeze(void); +_noreturn_ void freeze(void); bool oom_score_adjust_is_valid(int oa); diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index b91b09313..fd26ae713 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -985,8 +985,7 @@ int getpeersec(int fd, char **ret) { if (isempty(s)) return -EOPNOTSUPP; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return 0; } diff --git a/src/systemd/src/basic/stdio-util.h b/src/systemd/src/basic/stdio-util.h index dbfafba26..d3fed365d 100644 --- a/src/systemd/src/basic/stdio-util.h +++ b/src/systemd/src/basic/stdio-util.h @@ -27,9 +27,11 @@ #include "macro.h" -#define xsprintf(buf, fmt, ...) \ - assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") +#define snprintf_ok(buf, len, fmt, ...) \ + ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len)) +#define xsprintf(buf, fmt, ...) \ + assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough") #define VA_FORMAT_ADVANCE(format, ap) \ do { \ diff --git a/src/systemd/src/basic/string-table.h b/src/systemd/src/basic/string-table.h index 4306b90f4..e78a6dbde 100644 --- a/src/systemd/src/basic/string-table.h +++ b/src/systemd/src/basic/string-table.h @@ -93,13 +93,11 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) #define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) @@ -111,8 +109,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ - struct __useless_struct_to_allow_trailing_semicolon__ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index 68e2e874b..801001645 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -214,7 +214,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { p = strv_length(*a); q = strv_length(b); - t = realloc(*a, sizeof(char*) * (p + q + 1)); + t = reallocarray(*a, p + q + 1, sizeof(char *)); if (!t) return -ENOMEM; @@ -341,8 +341,7 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; - l[n++] = word; - word = NULL; + l[n++] = TAKE_PTR(word); l[n] = NULL; } @@ -353,8 +352,7 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract return -ENOMEM; } - *t = l; - l = NULL; + *t = TAKE_PTR(l); return (int) n; } @@ -407,7 +405,7 @@ int strv_push(char ***l, char *value) { if (m < n) return -ENOMEM; - c = realloc_multiply(*l, sizeof(char*), m); + c = reallocarray(*l, m, sizeof(char*)); if (!c) return -ENOMEM; @@ -432,7 +430,7 @@ int strv_push_pair(char ***l, char *a, char *b) { if (m < n) return -ENOMEM; - c = realloc_multiply(*l, sizeof(char*), m); + c = reallocarray(*l, m, sizeof(char*)); if (!c) return -ENOMEM; @@ -546,7 +544,7 @@ int strv_extend_front(char ***l, const char *value) { if (!v) return -ENOMEM; - c = realloc_multiply(*l, sizeof(char*), m); + c = reallocarray(*l, m, sizeof(char*)); if (!c) { free(v); return -ENOMEM; @@ -861,7 +859,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) { k = strv_length(*l); - nl = realloc(*l, sizeof(char*) * (k + n + 1)); + nl = reallocarray(*l, k + n + 1, sizeof(char *)); if (!nl) return -ENOMEM; diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 7863a14fb..b0303a17f 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -181,11 +181,13 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, const void *p; int comparison; + assert(!size_multiply_overflow(nmemb, size)); + l = 0; u = nmemb; while (l < u) { idx = (l + u) / 2; - p = (const char *) base + idx * size; + p = (const uint8_t*) base + idx * size; comparison = compar(key, p, arg); if (comparison < 0) u = idx; diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 6f8d8bef3..19e9eae12 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -91,6 +91,19 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), void *arg); +/** + * Normal bsearch requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void* bsearch_safe(const void *key, const void *base, + size_t nmemb, size_t size, comparison_fn_t compar) { + if (nmemb <= 0) + return NULL; + + assert(base); + return bsearch(key, base, nmemb, size, compar); +} + /** * Normal qsort requires base to be nonnull. Here were require * that only if nmemb > 0. diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index b8e9b2e49..3217ac0d1 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -103,10 +103,7 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_ if (r < 0) return -errno; - r = s; - s = -1; - - return r; + return TAKE_FD(s); } static int arp_send_packet(int fd, int ifindex, diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 602bf08a6..ac9a7a31b 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -123,10 +123,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, if (r < 0) return -errno; - r = s; - s = -1; - - return r; + return TAKE_FD(s); } int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, @@ -211,10 +208,7 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { if (r < 0) return -errno; - r = s; - s = -1; - - return r; + return TAKE_FD(s); } int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 0489579e7..142e39bc6 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -253,10 +253,8 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c if (message_type == 0) return -ENOMSG; - if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) { - *_error_message = error_message; - error_message = NULL; - } + if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) + *_error_message = TAKE_PTR(error_message); return message_type; } diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c index b3b8fddbc..70f590930 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-network.c +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -67,9 +67,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { if (r < 0) return -errno; - r = s; - s = -1; - return r; + return TAKE_FD(s); } int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index df96ad739..2b3c8ceb5 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -617,8 +617,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * idx++; } - *str_arr = names; - names = NULL; + *str_arr = TAKE_PTR(names); return idx; diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index cb3841ef2..c653813cf 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -92,8 +92,5 @@ int lldp_network_bind_raw_socket(int ifindex) { if (r < 0) return -errno; - r = fd; - fd = -1; - - return r; + return TAKE_FD(fd); } diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 94386e486..00a56c820 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -276,10 +276,9 @@ int config_parse_ifalias(const char *unit, } free(*s); - if (*n) { - *s = n; - n = NULL; - } else + if (*n) + *s = TAKE_PTR(n); + else *s = NULL; return 0; @@ -424,7 +423,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { if (r == 0) break; - new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); + new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr)); if (!new_addresses) return -ENOMEM; else @@ -437,8 +436,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { size++; } - *ret = addresses; - addresses = NULL; + *ret = TAKE_PTR(addresses); return size; } @@ -478,7 +476,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { if (r == 0) break; - new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); + new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr)); if (!new_addresses) return -ENOMEM; else @@ -491,8 +489,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { size++; } - *ret = addresses; - addresses = NULL; + *ret = TAKE_PTR(addresses); return size; } @@ -585,8 +582,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_size = size; *ret_allocated = allocated; - *ret = routes; - routes = NULL; + *ret = TAKE_PTR(routes); return 0; } diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 33f3469f0..9cf49747e 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -354,9 +354,10 @@ int sd_dhcp_client_set_client_id( * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -int sd_dhcp_client_set_iaid_duid( +static int dhcp_client_set_iaid_duid( sd_dhcp_client *client, uint32_t iaid, + bool append_iaid, uint16_t duid_type, const void *duid, size_t duid_len) { @@ -377,15 +378,17 @@ int sd_dhcp_client_set_iaid_duid( zero(client->client_id); client->client_id.type = 255; - /* If IAID is not configured, generate it. */ - if (iaid == 0) { - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, - client->mac_addr_len, - &client->client_id.ns.iaid); - if (r < 0) - return r; - } else - client->client_id.ns.iaid = htobe32(iaid); + if (append_iaid) { + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = htobe32(iaid); + } if (duid != NULL) { client->client_id.ns.duid.type = htobe16(duid_type); @@ -399,7 +402,7 @@ int sd_dhcp_client_set_iaid_duid( return -EOPNOTSUPP; client->client_id_len = sizeof(client->client_id.type) + len + - sizeof(client->client_id.ns.iaid); + (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { log_dhcp_client(client, "Configured IAID+DUID, restarting."); @@ -410,6 +413,23 @@ int sd_dhcp_client_set_iaid_duid( return 0; } +int sd_dhcp_client_set_iaid_duid( + sd_dhcp_client *client, + uint32_t iaid, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len); +} + +int sd_dhcp_client_set_duid( + sd_dhcp_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len); +} + int sd_dhcp_client_set_hostname( sd_dhcp_client *client, const char *hostname) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index 2e88e3987..9db0a9389 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -807,8 +807,7 @@ int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***d pos = next_chunk; } - *domains = names; - names = NULL; + *domains = TAKE_PTR(names); return cnt; } diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index 8c807e0e2..89d18431e 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -295,8 +295,7 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) { if (r < 0) return r; - *ret = s; - s = NULL; + *ret = TAKE_PTR(s); return r; } @@ -601,8 +600,7 @@ int dns_name_endswith(const char *name, const char *suffix) { /* Not the same, let's jump back, and try with the next label again */ s = suffix; - n = saved_n; - saved_n = NULL; + n = TAKE_PTR(saved_n); } } } diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 6eb9eb61a..789cc5017 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -132,6 +132,11 @@ int sd_dhcp_client_set_iaid_duid( uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp_client_set_duid( + sd_dhcp_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len); int sd_dhcp_client_get_client_id( sd_dhcp_client *client, uint8_t *type,