systemd: merge branch systemd into master
This commit is contained in:
@@ -25,6 +25,10 @@
|
||||
/* Gettext package */
|
||||
#mesondefine GETTEXT_PACKAGE
|
||||
|
||||
/* Define to 1 if you have the declaration of `reallocarray', and to 0 if
|
||||
you don't. */
|
||||
#mesondefine HAVE_DECL_REALLOCARRAY
|
||||
|
||||
/* Define to 1 if you have the declaration of `explicit_bzero', and to 0 if
|
||||
you don't. */
|
||||
#mesondefine HAVE_DECL_EXPLICIT_BZERO
|
||||
|
@@ -75,6 +75,12 @@ AC_CHECK_DECLS([
|
||||
#include <string.h>
|
||||
]])
|
||||
|
||||
AC_CHECK_DECLS([
|
||||
reallocarray],
|
||||
[], [], [[
|
||||
#include <malloc.h>
|
||||
]])
|
||||
|
||||
AC_CHECK_HEADERS(sys/auxv.h)
|
||||
|
||||
AC_CHECK_DECLS([getrandom],
|
||||
|
@@ -105,6 +105,7 @@ config_h.set10('HAVE_GETRANDOM', use_sys_random or cc.has_function('getrandom',
|
||||
# FIXME secure_getenv check is not useful?
|
||||
config_h.set('HAVE_SECURE_GETENV', cc.has_function('secure_getenv'))
|
||||
config_h.set('HAVE___SECURE_GETENV', cc.has_function('__secure_getenv'))
|
||||
config_h.set10('HAVE_DECL_REALLOCARRAY', cc.has_function('reallocarray', prefix: '#include <malloc.h>'))
|
||||
config_h.set10('HAVE_DECL_EXPLICIT_BZERO', cc.has_function('explicit_bzero', prefix: '#include <string.h>'))
|
||||
|
||||
# types
|
||||
|
@@ -26,12 +26,16 @@
|
||||
#include <sys/resource.h>
|
||||
#include <time.h>
|
||||
|
||||
#define noreturn G_GNUC_NORETURN
|
||||
|
||||
#ifndef CLOCK_BOOTTIME
|
||||
#define CLOCK_BOOTTIME 7
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1
|
||||
#define HAVE_REALLOCARRAY 1
|
||||
#else
|
||||
#define HAVE_REALLOCARRAY 0
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1
|
||||
#define HAVE_EXPLICIT_BZERO 1
|
||||
#else
|
||||
|
@@ -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_; \
|
||||
})
|
||||
|
@@ -196,8 +196,7 @@ finish:
|
||||
|
||||
finish_force_next:
|
||||
s[sz] = 0;
|
||||
*ret = s;
|
||||
s = NULL;
|
||||
*ret = TAKE_PTR(s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -194,12 +194,6 @@ int fd_cloexec(int fd, bool cloexec) {
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
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;
|
||||
|
||||
@@ -371,14 +365,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;
|
||||
@@ -431,7 +432,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;
|
||||
@@ -488,10 +488,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:
|
||||
@@ -528,10 +525,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:
|
||||
@@ -547,12 +541,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:
|
||||
@@ -621,3 +610,139 @@ int fd_move_above_stdio(int fd) {
|
||||
(void) close(fd);
|
||||
return copy;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
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;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
@@ -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);
|
||||
|
@@ -334,8 +334,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;
|
||||
@@ -367,11 +366,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,
|
||||
@@ -408,10 +407,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;
|
||||
}
|
||||
@@ -431,10 +428,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;
|
||||
}
|
||||
@@ -456,7 +451,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;
|
||||
@@ -471,10 +466,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;
|
||||
}
|
||||
@@ -501,7 +494,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;
|
||||
@@ -516,10 +509,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;
|
||||
}
|
||||
@@ -531,10 +522,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;
|
||||
}
|
||||
@@ -546,10 +535,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;
|
||||
}
|
||||
@@ -560,10 +547,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;
|
||||
}
|
||||
@@ -575,10 +560,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;
|
||||
}
|
||||
@@ -589,10 +572,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;
|
||||
}
|
||||
@@ -637,14 +618,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(
|
||||
@@ -1465,8 +1444,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;
|
||||
}
|
||||
@@ -1552,8 +1530,7 @@ int read_nul_string(FILE *f, char **ret) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret = x;
|
||||
x = NULL;
|
||||
*ret = TAKE_PTR(x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -465,10 +465,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;
|
||||
}
|
||||
@@ -586,6 +584,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
|
||||
@@ -636,9 +638,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)
|
||||
@@ -692,6 +704,8 @@ 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 (flags & CHASE_TRAIL_SLASH)
|
||||
if (!strextend(&done, "/", NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -739,8 +753,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;
|
||||
}
|
||||
@@ -845,10 +858,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';
|
||||
@@ -859,8 +871,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) {
|
||||
@@ -870,27 +881,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;
|
||||
@@ -898,10 +982,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;
|
||||
}
|
||||
@@ -985,8 +1068,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;
|
||||
|
@@ -20,6 +20,7 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
@@ -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;
|
||||
|
@@ -586,7 +586,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);
|
||||
|
@@ -149,19 +149,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,
|
||||
@@ -204,7 +191,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,
|
||||
@@ -213,7 +200,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,
|
||||
|
@@ -53,6 +53,26 @@
|
||||
#else
|
||||
#define _fallthrough_
|
||||
#endif
|
||||
/* Define C11 noreturn without <stdnoreturn.h> 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
|
||||
|
||||
#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__)
|
||||
/* Temporarily disable some warnings */
|
||||
@@ -423,21 +443,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
|
||||
* compiler versions */
|
||||
#ifndef noreturn
|
||||
#if defined(__STDC_VERSION__) && __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"
|
||||
|
@@ -327,8 +327,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;
|
||||
}
|
||||
@@ -375,12 +374,13 @@ finish:
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
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
|
||||
@@ -393,7 +393,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)
|
||||
@@ -491,17 +491,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)
|
||||
@@ -536,30 +537,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
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;
|
||||
|
@@ -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));
|
||||
|
@@ -293,8 +293,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;
|
||||
|
@@ -29,8 +29,14 @@
|
||||
#include "time-util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#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
|
||||
|
@@ -175,7 +175,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;
|
||||
|
||||
|
@@ -628,8 +628,7 @@ int get_process_environ(pid_t pid, char **env) {
|
||||
} else
|
||||
outcome[sz] = '\0';
|
||||
|
||||
*env = outcome;
|
||||
outcome = NULL;
|
||||
*env = TAKE_PTR(outcome);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -994,7 +993,7 @@ bool is_main_thread(void) {
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
noreturn void freeze(void) {
|
||||
_noreturn_ void freeze(void) {
|
||||
|
||||
log_close();
|
||||
|
||||
@@ -1174,6 +1173,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
|
||||
@@ -1194,12 +1194,20 @@ pid_t getpid_cached(void) {
|
||||
|
||||
new_pid = raw_getpid();
|
||||
|
||||
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;
|
||||
return new_pid;
|
||||
}
|
||||
@@ -1437,8 +1445,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 */
|
||||
@@ -1467,7 +1474,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",
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -988,8 +988,7 @@ int getpeersec(int fd, char **ret) {
|
||||
if (isempty(s))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
*ret = s;
|
||||
s = NULL;
|
||||
*ret = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -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 { \
|
||||
|
@@ -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)
|
||||
|
@@ -216,7 +216,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;
|
||||
|
||||
@@ -344,8 +344,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;
|
||||
}
|
||||
@@ -356,8 +355,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;
|
||||
}
|
||||
@@ -411,7 +409,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;
|
||||
|
||||
@@ -436,7 +434,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;
|
||||
|
||||
@@ -550,7 +548,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;
|
||||
@@ -865,7 +863,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;
|
||||
|
||||
|
@@ -186,11 +186,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;
|
||||
|
@@ -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.
|
||||
|
@@ -105,10 +105,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,
|
||||
|
@@ -125,10 +125,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,
|
||||
@@ -213,10 +210,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,
|
||||
|
@@ -255,10 +255,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;
|
||||
}
|
||||
|
@@ -69,9 +69,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,
|
||||
|
@@ -619,8 +619,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;
|
||||
|
||||
|
@@ -94,8 +94,5 @@ int lldp_network_bind_raw_socket(int ifindex) {
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = fd;
|
||||
fd = -1;
|
||||
|
||||
return r;
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
|
@@ -279,10 +279,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;
|
||||
@@ -428,7 +427,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
|
||||
@@ -441,8 +440,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = addresses;
|
||||
addresses = NULL;
|
||||
*ret = TAKE_PTR(addresses);
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -482,7 +480,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
|
||||
@@ -495,8 +493,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
|
||||
size++;
|
||||
}
|
||||
|
||||
*ret = addresses;
|
||||
addresses = NULL;
|
||||
*ret = TAKE_PTR(addresses);
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -589,8 +586,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;
|
||||
}
|
||||
|
@@ -358,9 +358,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) {
|
||||
@@ -381,6 +382,7 @@ int sd_dhcp_client_set_iaid_duid(
|
||||
zero(client->client_id);
|
||||
client->client_id.type = 255;
|
||||
|
||||
if (append_iaid) {
|
||||
/* If IAID is not configured, generate it. */
|
||||
if (iaid == 0) {
|
||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
|
||||
@@ -390,6 +392,7 @@ int sd_dhcp_client_set_iaid_duid(
|
||||
return r;
|
||||
} else
|
||||
client->client_id.ns.iaid = htobe32(iaid);
|
||||
}
|
||||
|
||||
if (duid != NULL) {
|
||||
client->client_id.ns.duid.type = htobe16(duid_type);
|
||||
@@ -403,7 +406,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.");
|
||||
@@ -413,6 +416,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);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int sd_dhcp_client_set_hostname(
|
||||
|
@@ -809,8 +809,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;
|
||||
}
|
||||
|
@@ -302,8 +302,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;
|
||||
}
|
||||
@@ -610,8 +609,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user