Commit be8f7b5a authored by Beniamino Galvani's avatar Beniamino Galvani

systemd: merge branch systemd into master

parents fe52a946 55c47d4e
Pipeline #46816 failed with stages
in 50 minutes and 42 seconds
......@@ -1662,7 +1662,6 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/sd-adapt-shared/device-nodes.h \
shared/systemd/sd-adapt-shared/dirent-util.h \
shared/systemd/sd-adapt-shared/errno-list.h \
shared/systemd/sd-adapt-shared/format-util.h \
shared/systemd/sd-adapt-shared/glob-util.h \
shared/systemd/sd-adapt-shared/gunicode.h \
shared/systemd/sd-adapt-shared/ioprio.h \
......@@ -1702,6 +1701,8 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
shared/systemd/src/basic/fd-util.h \
shared/systemd/src/basic/fileio.c \
shared/systemd/src/basic/fileio.h \
shared/systemd/src/basic/format-util.c \
shared/systemd/src/basic/format-util.h \
shared/systemd/src/basic/fs-util.c \
shared/systemd/src/basic/fs-util.h \
shared/systemd/src/basic/hash-funcs.c \
......
......@@ -118,14 +118,26 @@
/* Define to 1 if libsystemd-login is available */
#mesondefine SESSION_TRACKING_SYSTEMD
/* The size of `pid_t', as computed by sizeof. */
#mesondefine SIZEOF_PID_T
/* The size of `uid_t', as computed by sizeof. */
#mesondefine SIZEOF_UID_T
/* The size of `gid_t', as computed by sizeof. */
#mesondefine SIZEOF_GID_T
/* The size of `dev_t', as computed by sizeof. */
#mesondefine SIZEOF_DEV_T
/* The size of `ino_t', as computed by sizeof. */
#mesondefine SIZEOF_INO_T
/* The size of `time_t', as computed by sizeof. */
#mesondefine SIZEOF_TIME_T
/* The size of `pid_t', as computed by sizeof. */
#mesondefine SIZEOF_PID_T
/* The size of `rlim_t', as computed by sizeof. */
#mesondefine SIZEOF_RLIM_T
/* Define to 1 to use ConsoleKit2 suspend api */
#mesondefine SUSPEND_RESUME_CONSOLEKIT
......
......@@ -65,9 +65,13 @@ dnl
dnl Checks for typedefs, structures, and compiler characteristics.
dnl
AC_TYPE_PID_T
AC_CHECK_SIZEOF(pid_t)
AC_CHECK_SIZEOF(uid_t)
AC_CHECK_SIZEOF(gid_t)
AC_CHECK_SIZEOF(dev_t)
AC_CHECK_SIZEOF(ino_t)
AC_CHECK_SIZEOF(time_t)
AC_CHECK_SIZEOF(pid_t)
AC_CHECK_SIZEOF(rlim_t,,[[#include <sys/resource.h>]])
AC_CHECK_DECLS([
explicit_bzero],
......
......@@ -98,9 +98,13 @@ config_h.set10('HAVE_DECL_EXPLICIT_BZERO', cc.has_function('explicit_bzero', pre
config_h.set10('HAVE_DECL_MEMFD_CREATE', cc.has_function('memfd_create', prefix: '#include <sys/mman.h>'))
# types
config_h.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix: '#include <sys/types.h>'))
config_h.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix: '#include <sys/types.h>'))
config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix: '#include <sys/types.h>'))
config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix : '#include <sys/types.h>'))
config_h.set('SIZEOF_UID_T', cc.sizeof('uid_t', prefix : '#include <sys/types.h>'))
config_h.set('SIZEOF_GID_T', cc.sizeof('gid_t', prefix : '#include <sys/types.h>'))
config_h.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix : '#include <sys/types.h>'))
config_h.set('SIZEOF_INO_T', cc.sizeof('ino_t', prefix : '#include <sys/types.h>'))
config_h.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
config_h.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h>'))
if not cc.has_type('pid_t', prefix: '#include <sys/types.h>')
config_h.set('pid_t', 'int')
......
......@@ -214,6 +214,7 @@ libnm_systemd_shared = static_library(
'systemd/src/basic/extract-word.c',
'systemd/src/basic/fd-util.c',
'systemd/src/basic/fileio.c',
'systemd/src/basic/format-util.c',
'systemd/src/basic/fs-util.c',
'systemd/src/basic/hash-funcs.c',
'systemd/src/basic/hashmap.c',
......
......@@ -75,7 +75,7 @@ bool env_value_is_valid(const char *e) {
* either. Discounting the shortest possible variable name of
* length 1, the equal sign and trailing NUL this hence leaves
* ARG_MAX-3 as longest possible variable value. */
if (strlen(e) > (size_t) sysconf(_SC_ARG_MAX) - 3)
if (strlen(e) > sc_arg_max() - 3)
return false;
return true;
......@@ -98,7 +98,7 @@ bool env_assignment_is_valid(const char *e) {
* be > ARG_MAX, hence the individual variable assignments
* cannot be either, but let's leave room for one trailing NUL
* byte. */
if (strlen(e) > (size_t) sysconf(_SC_ARG_MAX) - 1)
if (strlen(e) > sc_arg_max() - 1)
return false;
return true;
......@@ -691,7 +691,7 @@ char **replace_env_argv(char **argv, char **env) {
if (e) {
int r;
r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES);
r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
if (r < 0) {
ret[k] = NULL;
strv_free(ret);
......
......@@ -4,10 +4,17 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include "macro.h"
#include "string.h"
static inline size_t sc_arg_max(void) {
long l = sysconf(_SC_ARG_MAX);
assert(l > 0);
return (size_t) l;
}
bool env_name_is_valid(const char *e);
bool env_value_is_valid(const char *e);
bool env_assignment_is_valid(const char *e);
......
......@@ -370,34 +370,81 @@ int cunescape(const char *s, UnescapeFlags flags, char **ret) {
return cunescape_length(s, strlen(s), flags, ret);
}
char *xescape(const char *s, const char *bad) {
char *r, *t;
#if 0 /* NM_IGNORED */
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
char *ans, *t, *prev, *prev2;
const char *f;
/* Escapes all chars in bad, in addition to \ and all special
* chars, in \xFF style escaping. May be reversed with
* cunescape(). */
/* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
* reversed with cunescape(). If eight_bits is true, characters >= 127 are let through unchanged.
* This corresponds to non-ASCII printable characters in pre-unicode encodings.
*
* If console_width is reached, output is truncated and "..." is appended. */
r = new(char, strlen(s) * 4 + 1);
if (!r)
if (console_width == 0)
return strdup("");
ans = new(char, MIN(strlen(s), console_width) * 4 + 1);
if (!ans)
return NULL;
for (f = s, t = r; *f; f++) {
memset(ans, '_', MIN(strlen(s), console_width) * 4);
ans[MIN(strlen(s), console_width) * 4] = 0;
for (f = s, t = prev = prev2 = ans; ; f++) {
char *tmp_t = t;
if (!*f) {
*t = 0;
return ans;
}
if ((unsigned char) *f < ' ' || (!eight_bits && (unsigned char) *f >= 127) ||
*f == '\\' || strchr(bad, *f)) {
if ((size_t) (t - ans) + 4 > console_width)
break;
if ((*f < ' ') || (*f >= 127) ||
(*f == '\\') || strchr(bad, *f)) {
*(t++) = '\\';
*(t++) = 'x';
*(t++) = hexchar(*f >> 4);
*(t++) = hexchar(*f);
} else
} else {
if ((size_t) (t - ans) + 1 > console_width)
break;
*(t++) = *f;
}
/* We might need to go back two cycles to fit three dots, so remember two positions */
prev2 = prev;
prev = tmp_t;
}
*t = 0;
/* We can just write where we want, since chars are one-byte */
size_t c = MIN(console_width, 3u); /* If the console is too narrow, write fewer dots */
size_t off;
if (console_width - c >= (size_t) (t - ans))
off = (size_t) (t - ans);
else if (console_width - c >= (size_t) (prev - ans))
off = (size_t) (prev - ans);
else if (console_width - c >= (size_t) (prev2 - ans))
off = (size_t) (prev2 - ans);
else
off = console_width - c;
assert(off <= (size_t) (t - ans));
return r;
memcpy(ans + off, "...", c);
ans[off + c] = '\0';
return ans;
}
char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) {
if (eight_bit)
return xescape_full(str, "", console_width, true);
else
return utf8_escape_non_printable_full(str, console_width);
}
#endif /* NM_IGNORED */
char *octescape(const char *s, size_t len) {
char *r, *t;
......
......@@ -46,8 +46,12 @@ int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **r
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
char *xescape(const char *s, const char *bad);
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
static inline char *xescape(const char *s, const char *bad) {
return xescape_full(s, bad, SIZE_MAX, false);
}
char *octescape(const char *s, size_t len);
char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit);
char *shell_escape(const char *s, const char *bad);
char* shell_maybe_quote(const char *s, EscapeStyle style);
......@@ -137,7 +137,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
for (;; (*p)++, c = **p) {
if (c == 0)
goto finish_force_terminate;
else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_QUOTES)) {
else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_UNQUOTE)) {
quote = c;
break;
} else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
......
......@@ -7,7 +7,7 @@ typedef enum ExtractFlags {
EXTRACT_RELAX = 1 << 0,
EXTRACT_CUNESCAPE = 1 << 1,
EXTRACT_CUNESCAPE_RELAX = 1 << 2,
EXTRACT_QUOTES = 1 << 3,
EXTRACT_UNQUOTE = 1 << 3,
EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 4,
EXTRACT_RETAIN_ESCAPE = 1 << 5,
} ExtractFlags;
......
......@@ -23,6 +23,7 @@
#include "log.h"
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
#include "stdio-util.h"
......@@ -177,6 +178,12 @@ int write_string_file_ts(
/* We don't know how to verify whether the file contents was already on-disk. */
assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
if (flags & WRITE_STRING_FILE_MKDIR_0755) {
r = mkdir_parents(fn, 0755);
if (r < 0)
return r;
}
if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE);
......@@ -589,10 +596,7 @@ static int search_and_fopen_internal(const char *path, const char *mode, const c
_cleanup_free_ char *p = NULL;
FILE *f;
if (root)
p = strjoin(root, *i, "/", path);
else
p = strjoin(*i, "/", path);
p = path_join(root, *i, path);
if (!p)
return -ENOMEM;
......
......@@ -21,6 +21,7 @@ typedef enum {
WRITE_STRING_FILE_SYNC = 1 << 4,
WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
WRITE_STRING_FILE_NOFOLLOW = 1 << 6,
WRITE_STRING_FILE_MKDIR_0755 = 1 << 7,
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
......
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "nm-sd-adapt-shared.h"
#include <stdio.h>
#include "format-util.h"
#include "memory-util.h"
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) {
/* Buffer is always cleared */
memzero(buf, IF_NAMESIZE + 1);
return if_indextoname(ifindex, buf);
}
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
typedef struct {
const char *suffix;
uint64_t factor;
} suffix_table;
static const suffix_table table_iec[] = {
{ "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "M", UINT64_C(1024)*UINT64_C(1024) },
{ "K", UINT64_C(1024) },
}, table_si[] = {
{ "E", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
{ "P", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
{ "T", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
{ "G", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
{ "M", UINT64_C(1000)*UINT64_C(1000) },
{ "K", UINT64_C(1000) },
};
const suffix_table *table;
size_t n, i;
assert_cc(ELEMENTSOF(table_iec) == ELEMENTSOF(table_si));
if (t == (uint64_t) -1)
return NULL;
table = flag & FORMAT_BYTES_USE_IEC ? table_iec : table_si;
n = ELEMENTSOF(table_iec);
for (i = 0; i < n; i++)
if (t >= table[i].factor) {
if (flag & FORMAT_BYTES_BELOW_POINT) {
snprintf(buf, l,
"%" PRIu64 ".%" PRIu64 "%s",
t / table[i].factor,
i != n - 1 ?
(t / table[i + 1].factor * UINT64_C(10) / table[n - 1].factor) % UINT64_C(10):
(t * UINT64_C(10) / table[i].factor) % UINT64_C(10),
table[i].suffix);
} else
snprintf(buf, l,
"%" PRIu64 "%s",
t / table[i].factor,
table[i].suffix);
goto finish;
}
snprintf(buf, l, "%" PRIu64 "%s", t, flag & FORMAT_BYTES_TRAILING_B ? "B" : "");
finish:
buf[l-1] = 0;
return buf;
}
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <inttypes.h>
#include <net/if.h>
#include <stdbool.h>
#if SIZEOF_PID_T == 4
# define PID_PRI PRIi32
#elif SIZEOF_PID_T == 2
# define PID_PRI PRIi16
#else
# error Unknown pid_t size
#endif
#define PID_FMT "%" PID_PRI
#if SIZEOF_UID_T == 4
# define UID_FMT "%" PRIu32
#elif SIZEOF_UID_T == 2
# define UID_FMT "%" PRIu16
#else
# error Unknown uid_t size
#endif
#if SIZEOF_GID_T == 4
# define GID_FMT "%" PRIu32
#elif SIZEOF_GID_T == 2
# define GID_FMT "%" PRIu16
#else
# error Unknown gid_t size
#endif
#if SIZEOF_TIME_T == 8
# define PRI_TIME PRIi64
#elif SIZEOF_TIME_T == 4
# define PRI_TIME "li"
#else
# error Unknown time_t size
#endif
#if defined __x86_64__ && defined __ILP32__
# define PRI_TIMEX PRIi64
#else
# define PRI_TIMEX "li"
#endif
#if SIZEOF_RLIM_T == 8
# define RLIM_FMT "%" PRIu64
#elif SIZEOF_RLIM_T == 4
# define RLIM_FMT "%" PRIu32
#else
# error Unknown rlim_t size
#endif
#if SIZEOF_DEV_T == 8
# define DEV_FMT "%" PRIu64
#elif SIZEOF_DEV_T == 4
# define DEV_FMT "%" PRIu32
#else
# error Unknown dev_t size
#endif
#if SIZEOF_INO_T == 8
# define INO_FMT "%" PRIu64
#elif SIZEOF_INO_T == 4
# define INO_FMT "%" PRIu32
#else
# error Unknown ino_t size
#endif
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]);
typedef enum {
FORMAT_BYTES_USE_IEC = 1 << 0,
FORMAT_BYTES_BELOW_POINT = 1 << 1,
FORMAT_BYTES_TRAILING_B = 1 << 2,
} FormatBytesFlag;
#define FORMAT_BYTES_MAX 8
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
}
......@@ -218,113 +218,65 @@ int readlink_and_make_absolute(const char *p, char **r) {
}
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;
bool st_valid = false;
struct stat st;
int r;
assert(path);
/* Under the assumption that we are running privileged we first change the access mode and only then
* hand out ownership to avoid a window where access is too open. */
fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
* mode/owner on the same file */
if (fd < 0)
return -errno;
xsprintf(fd_path, "/proc/self/fd/%i", fd);
if (mode != MODE_INVALID) {
if ((mode & S_IFMT) != 0) {
if (stat(fd_path, &st) < 0)
return -errno;
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
return -EINVAL;
st_valid = true;
}
if (chmod(fd_path, mode & 07777) < 0) {
r = -errno;
if (!st_valid && stat(fd_path, &st) < 0)
return -errno;
if ((mode & 07777) != (st.st_mode & 07777))
return r;
st_valid = true;
}
}
if (uid != UID_INVALID || gid != GID_INVALID) {
if (chown(fd_path, uid, gid) < 0) {
r = -errno;
if (!st_valid && stat(fd_path, &st) < 0)
return -errno;
if (uid != UID_INVALID && st.st_uid != uid)
return r;
if (gid != GID_INVALID && st.st_gid != gid)
return r;
}
}
return 0;
return fchmod_and_chown(fd, mode, uid, gid);
}
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
bool st_valid = false;
bool do_chown, do_chmod;
struct stat st;
int r;
/* Under the assumption that we are running privileged we first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
/* Change ownership and access mode of the specified fd. Tries to do so safely, ensuring that at no
* point in time the access mode is above the old access mode under the old ownership or the new
* access mode under the new ownership. Note: this call tries hard to leave the access mode
* unaffected if the uid/gid is changed, i.e. it undoes implicit suid/sgid dropping the kernel does
* on chown().
*
* This call is happy with O_PATH fds. */
if (mode != MODE_INVALID) {
if ((mode & S_IFMT) != 0) {
if (fstat(fd, &st) < 0)
return -errno;
if (fstat(fd, &st) < 0)
return -errno;
do_chown =
(uid != UID_INVALID && st.st_uid != uid) ||
(gid != GID_INVALID && st.st_gid != gid);
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
return -EINVAL;
do_chmod =
!S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
* modifies the access mode too */
st_valid = true;
}
if (mode == MODE_INVALID)
mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
return -EINVAL; /* insist on the right file type if it was specified */
if (fchmod(fd, mode & 07777) < 0) {
r = -errno;
if (do_chown && do_chmod) {
mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
if (!st_valid && fstat(fd, &st) < 0)
if (((minimal ^ st.st_mode) & 07777) != 0)
if (fchmod_opath(fd, minimal & 07777) < 0)
return -errno;
if ((mode & 07777) != (st.st_mode & 07777))
return r;
st_valid = true;
}
}
if (uid != UID_INVALID || gid != GID_INVALID)
if (fchown(fd, uid, gid) < 0) {
r = -errno;
if (!st_valid && fstat(fd, &st) < 0)
return -errno;
if (do_chown)
if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0)
return -errno;
if (uid != UID_INVALID && st.st_uid != uid)
return r;
if (gid != GID_INVALID && st.st_gid != gid)
return r;
}
if (do_chmod)
if (fchmod_opath(fd, mode & 07777) < 0)
return -errno;
return 0;
return do_chown || do_chmod;
}
#endif /* NM_IGNORED */
......@@ -411,13 +363,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
* something fchown(), fchmod(), futimensat() don't allow. */
xsprintf(fdpath, "/proc/self/fd/%i", fd);
if (mode != MODE_INVALID)
if (chmod(fdpath, mode) < 0)
ret = -errno;
if (uid_is_valid(uid) || gid_is_valid(gid))
if (chown(fdpath, uid, gid) < 0 && ret >= 0)
ret = -errno;
ret = fchmod_and_chown(fd, mode, uid, gid);
if (stamp != USEC_INFINITY) {
struct timespec ts[2];
......@@ -1043,9 +989,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
/* Prefix what's left to do with what we just read, and start the loop again, but
* remain in the current directory. */
joined = strjoin(destination, todo);
joined = path_join(destination, todo);
} else
joined = strjoin("/", destination, todo);
joined = path_join("/", destination, todo);
if (!joined)
return -ENOMEM;
......
......@@ -7,12 +7,20 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "errno-util.h"
#include "time-util.h"
#define MODE_INVALID ((mode_t) -1)
/* The following macros add 1 when converting things, since 0 is a valid mode, while the pointer
* NULL is special */
#define PTR_TO_MODE(p) ((mode_t) ((uintptr_t) (p)-1))
#define MODE_TO_PTR(u) ((void *) ((uintptr_t) (u)+1))
int unlink_noerrno(const char *path);
int rmdir_parents(const char *path, const char *stop);
......
......@@ -13,6 +13,7 @@
#include "macro.h"
#include "memory-util.h"
#include "mempool.h"
#include "missing.h"
#include "process-util.h"
#include "random-util.h"
#include "set.h"
......@@ -287,7 +288,11 @@ _destructor_ static void cleanup_pools(void) {
/* The pool is only allocated by the main thread, but the memory can
* be passed to other threads. Let's clean up if we are the main thread
* and no other threads are live. */
if (!is_main_thread())
/* We build our own is_main_thread() here, which doesn't use C11
* TLS based caching of the result. That's because valgrind apparently
* doesn't like malloc() (which C11 TLS internally uses) to be called
* from a GCC destructors. */
if (getpid() != gettid())
return;
r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
......
......@@ -747,4 +747,16 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
}
DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
assert(addr);
siphash24_compress(addr, sizeof(*addr), state);
}
static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
return memcmp(a, b, sizeof(*a));
}
DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
#endif /* NM_IGNORED */
......@@ -72,3 +72,4 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
extern const struct hash_ops in_addr_data_hash_ops;
extern const struct hash_ops in6_addr_hash_ops;
......@@ -269,4 +269,86 @@ char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *f
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
return x;
}
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
char *x;
x = set_iovec_string_field(iovec, n_iovec, field, value);
free(value);
return x;
}
struct iovec_wrapper *iovw_new(void) {
return malloc0(sizeof(struct iovec_wrapper));
}
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
if (free_vectors)
for (size_t i = 0; i < iovw->count; i++)
free(iovw->iovec[i].iov_base);
iovw->iovec = mfree(iovw->iovec);
iovw->count = 0;