Merge pull request #34511 from YHNdnzj/strv-extend-strv-consume

basic/strv: introduce strv_extend_strv_consume()
This commit is contained in:
Yu Watanabe
2024-09-21 13:57:02 +09:00
committed by GitHub
29 changed files with 238 additions and 189 deletions

View File

@@ -43,7 +43,7 @@ void* greedy_realloc(
size_t need,
size_t size) {
size_t a, newalloc;
size_t newalloc;
void *q;
assert(p);
@@ -60,14 +60,13 @@ void* greedy_realloc(
return NULL;
newalloc = need * 2;
if (size_multiply_overflow(newalloc, size))
if (!MUL_ASSIGN_SAFE(&newalloc, size))
return NULL;
a = newalloc * size;
if (a < 64) /* Allocate at least 64 bytes */
a = 64;
if (newalloc < 64) /* Allocate at least 64 bytes */
newalloc = 64;
q = realloc(*p, a);
q = realloc(*p, newalloc);
if (!q)
return NULL;

View File

@@ -26,23 +26,23 @@ typedef void* (*mfree_func_t)(void *p);
#define alloca_safe(n) \
({ \
size_t _nn_ = n; \
size_t _nn_ = (n); \
assert(_nn_ <= ALLOCA_MAX); \
alloca(_nn_ == 0 ? 1 : _nn_); \
}) \
#define newa(t, n) \
({ \
size_t _n_ = n; \
assert(!size_multiply_overflow(sizeof(t), _n_)); \
(t*) alloca_safe(sizeof(t)*_n_); \
size_t _n_ = (n); \
assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t))); \
(t*) alloca_safe(_n_); \
})
#define newa0(t, n) \
({ \
size_t _n_ = n; \
assert(!size_multiply_overflow(sizeof(t), _n_)); \
(t*) alloca0((sizeof(t)*_n_)); \
size_t _n_ = (n); \
assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t))); \
(t*) alloca0(_n_); \
})
#define newdup(t, p, n) ((t*) memdup_multiply(p, n, sizeof(t)))

View File

@@ -796,10 +796,10 @@ int replace_env_full(
t = v;
}
r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
r = strv_extend_strv_consume(&unset_variables, TAKE_PTR(u), /* filter_duplicates= */ true);
if (r < 0)
return r;
r = strv_extend_strv(&bad_variables, b, /* filter_duplicates= */ true);
r = strv_extend_strv_consume(&bad_variables, TAKE_PTR(b), /* filter_duplicates= */ true);
if (r < 0)
return r;
@@ -931,11 +931,11 @@ int replace_env_argv(
return r;
n[++k] = NULL;
r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
r = strv_extend_strv_consume(&unset_variables, TAKE_PTR(u), /* filter_duplicates= */ true);
if (r < 0)
return r;
r = strv_extend_strv(&bad_variables, b, /*filter_duplicates= */ true);
r = strv_extend_strv_consume(&bad_variables, TAKE_PTR(b), /* filter_duplicates= */ true);
if (r < 0)
return r;
}

View File

@@ -368,17 +368,4 @@ assert_cc(sizeof(dummy_t) == 0);
((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
_current_++)
#define DECIMAL_STR_FMT(x) _Generic((x), \
char: "%c", \
bool: "%d", \
unsigned char: "%d", \
short: "%hd", \
unsigned short: "%hu", \
int: "%d", \
unsigned: "%u", \
long: "%ld", \
unsigned long: "%lu", \
long long: "%lld", \
unsigned long long: "%llu")
#include "log.h"

View File

@@ -35,7 +35,12 @@ static inline void* mempcpy_safe(void *dst, const void *src, size_t n) {
return mempcpy(dst, src, n);
}
#define mempcpy_typesafe(dst, src, n) (typeof((dst)[0])*) mempcpy_safe(dst, src, n)
#define mempcpy_typesafe(dst, src, n) \
({ \
size_t _sz_; \
assert_se(MUL_SAFE(&_sz_, sizeof((dst)[0]), n)); \
(typeof((dst)[0])*) mempcpy_safe(dst, src, _sz_); \
})
/* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */
static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {

View File

@@ -201,18 +201,17 @@ int strextendf_with_separator(char **x, const char *separator, const char *forma
char* strrep(const char *s, unsigned n);
#define strrepa(s, n) \
({ \
const char *_sss_ = (s); \
size_t _nnn_ = (n), _len_ = strlen(_sss_); \
assert(!size_multiply_overflow(_len_, _nnn_)); \
_len_ *= _nnn_; \
char *_d_, *_p_; \
_p_ = _d_ = newa(char, _len_ + 1); \
for (size_t _i_ = 0; _i_ < _nnn_; _i_++) \
_p_ = stpcpy(_p_, _sss_); \
*_p_ = 0; \
_d_; \
#define strrepa(s, n) \
({ \
const char *_sss_ = (s); \
size_t _nnn_ = (n), _len_ = strlen(_sss_); \
assert_se(MUL_ASSIGN_SAFE(&_len_, _nnn_)); \
char *_d_, *_p_; \
_p_ = _d_ = newa(char, _len_ + 1); \
for (size_t _i_ = 0; _i_ < _nnn_; _i_++) \
_p_ = stpcpy(_p_, _sss_); \
*_p_ = 0; \
_d_; \
})
int split_pair(const char *s, const char *sep, char **l, char **r);

View File

@@ -264,20 +264,18 @@ char** strv_new_internal(const char *x, ...) {
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
size_t p, q, i = 0;
char **t;
assert(a);
if (strv_isempty(b))
q = strv_length(b);
if (q == 0)
return 0;
p = strv_length(*a);
q = strv_length(b);
if (p >= SIZE_MAX - q)
return -ENOMEM;
t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
if (!t)
return -ENOMEM;
@@ -306,9 +304,67 @@ rollback:
return -ENOMEM;
}
int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates) {
_cleanup_strv_free_ char **b_consume = b;
size_t p, q, i;
assert(a);
q = strv_length(b);
if (q == 0)
return 0;
p = strv_length(*a);
if (p == 0) {
strv_free_and_replace(*a, b_consume);
if (filter_duplicates)
strv_uniq(*a);
return strv_length(*a);
}
if (p >= SIZE_MAX - q)
return -ENOMEM;
char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
if (!t)
return -ENOMEM;
t[p] = NULL;
*a = t;
if (!filter_duplicates) {
*mempcpy_typesafe(t + p, b, q) = NULL;
i = q;
} else {
i = 0;
STRV_FOREACH(s, b) {
if (strv_contains(t, *s)) {
free(*s);
continue;
}
t[p+i] = *s;
i++;
t[p+i] = NULL;
}
}
assert(i <= q);
b_consume = mfree(b_consume);
return (int) i;
}
int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix) {
int r;
assert(a);
STRV_FOREACH(s, b) {
char *v;
@@ -384,7 +440,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
}
int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
_cleanup_strv_free_ char **l = NULL;
char **l;
int r;
assert(t);
@@ -394,7 +450,7 @@ int strv_split_and_extend_full(char ***t, const char *s, const char *separators,
if (r < 0)
return r;
r = strv_extend_strv(t, l, filter_duplicates);
r = strv_extend_strv_consume(t, l, filter_duplicates);
if (r < 0)
return r;
@@ -987,10 +1043,16 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
return 0;
}
DEFINE_PRIVATE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
char **l;
int r;
assert(h);
assert(key);
assert(value);
l = hashmap_get(h, key);
if (l) {
/* A list for this key already exists, let's append to it if it is not listed yet */
@@ -1018,6 +1080,7 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
r = hashmap_put(h, t, l2);
if (r < 0)
return r;
TAKE_PTR(t);
TAKE_PTR(l2);
}
@@ -1028,6 +1091,10 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
int r;
assert(h);
assert(key);
assert(value);
r = _hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@@ -1038,6 +1105,10 @@ int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HA
int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS) {
int r;
assert(h);
assert(key);
assert(value);
r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@@ -1045,8 +1116,6 @@ int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const
return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
}
DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
int strv_rebreak_lines(char **l, size_t width, char ***ret) {
_cleanup_strv_free_ char **broken = NULL;
int r;

View File

@@ -44,10 +44,13 @@ int strv_copy_unless_empty(char * const *l, char ***ret);
size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix);
static inline int strv_extend_strv_concat(char ***a, const char* const *b, const char *suffix) {
return strv_extend_strv_biconcat(a, NULL, b, suffix);
}
int strv_prepend(char ***l, const char *value);
/* _with_size() are lower-level functions where the size can be provided externally,
@@ -253,7 +256,6 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
#define strv_free_and_replace(a, b) \
free_and_replace_full(a, b, strv_free)
extern const struct hash_ops string_strv_hash_ops;
int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS);
#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS)

View File

@@ -2046,7 +2046,7 @@ int exec_command_set(ExecCommand *c, const char *path, ...) {
}
int exec_command_append(ExecCommand *c, const char *path, ...) {
_cleanup_strv_free_ char **l = NULL;
char **l;
va_list ap;
int r;
@@ -2060,7 +2060,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
if (!l)
return -ENOMEM;
r = strv_extend_strv(&c->argv, l, false);
r = strv_extend_strv_consume(&c->argv, l, /* filter_duplicates = */ false);
if (r < 0)
return r;

View File

@@ -106,13 +106,9 @@ int unit_load_dropin(Unit *u) {
if (r <= 0)
return 0;
if (!u->dropin_paths)
u->dropin_paths = TAKE_PTR(l);
else {
r = strv_extend_strv(&u->dropin_paths, l, true);
if (r < 0)
return log_oom();
}
r = strv_extend_strv_consume(&u->dropin_paths, TAKE_PTR(l), /* filter_duplicates = */ true);
if (r < 0)
return log_oom();
u->dropin_mtime = 0;
STRV_FOREACH(f, u->dropin_paths) {

View File

@@ -2779,10 +2779,8 @@ int config_parse_pass_environ(
void *data,
void *userdata) {
_cleanup_strv_free_ char **n = NULL;
char ***passenv = ASSERT_PTR(data);
const Unit *u = userdata;
char*** passenv = ASSERT_PTR(data);
size_t nlen = 0;
int r;
assert(filename);
@@ -2795,6 +2793,8 @@ int config_parse_pass_environ(
return 0;
}
_cleanup_strv_free_ char **n = NULL;
for (const char *p = rvalue;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
@@ -2825,19 +2825,14 @@ int config_parse_pass_environ(
continue;
}
if (!GREEDY_REALLOC(n, nlen + 2))
return log_oom();
n[nlen++] = TAKE_PTR(k);
n[nlen] = NULL;
}
if (n) {
r = strv_extend_strv(passenv, n, true);
if (r < 0)
if (strv_consume(&n, TAKE_PTR(k)) < 0)
return log_oom();
}
r = strv_extend_strv_consume(passenv, TAKE_PTR(n), /* filter_duplicates = */ true);
if (r < 0)
return log_oom();
return 0;
}
@@ -2853,10 +2848,8 @@ int config_parse_unset_environ(
void *data,
void *userdata) {
_cleanup_strv_free_ char **n = NULL;
char*** unsetenv = ASSERT_PTR(data);
char ***unsetenv = ASSERT_PTR(data);
const Unit *u = userdata;
size_t nlen = 0;
int r;
assert(filename);
@@ -2869,6 +2862,8 @@ int config_parse_unset_environ(
return 0;
}
_cleanup_strv_free_ char **n = NULL;
for (const char *p = rvalue;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
@@ -2899,19 +2894,14 @@ int config_parse_unset_environ(
continue;
}
if (!GREEDY_REALLOC(n, nlen + 2))
return log_oom();
n[nlen++] = TAKE_PTR(k);
n[nlen] = NULL;
}
if (n) {
r = strv_extend_strv(unsetenv, n, true);
if (r < 0)
if (strv_consume(&n, TAKE_PTR(k)) < 0)
return log_oom();
}
r = strv_extend_strv_consume(unsetenv, TAKE_PTR(n), /* filter_duplicates = */ true);
if (r < 0)
return log_oom();
return 0;
}

View File

@@ -3652,7 +3652,7 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(r, "Failed to parse SSH authorized keys list: %m");
}
r = strv_extend_strv(&l, add, true);
r = strv_extend_strv_consume(&l, TAKE_PTR(add), /* filter_duplicates = */ true);
if (r < 0)
return log_oom();

View File

@@ -424,7 +424,7 @@ int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t
if (r < 0)
return r;
return strv_extend_strv(&lease->domains, domains, true);
return strv_extend_strv_consume(&lease->domains, TAKE_PTR(domains), /* filter_duplicates = */ true);
}
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret) {

View File

@@ -410,7 +410,7 @@ static int varlink_connect_ssh_exec(sd_varlink **ret, const char *where) {
full_cmdline = strv_new("ssh", "-e", "none", "-T", h, "env", "SYSTEMD_VARLINK_LISTEN=-");
if (!full_cmdline)
return log_oom_debug();
r = strv_extend_strv(&full_cmdline, cmdline, /* filter_duplicates= */ false);
r = strv_extend_strv_consume(&full_cmdline, TAKE_PTR(cmdline), /* filter_duplicates= */ false);
if (r < 0)
return log_oom_debug();

View File

@@ -23,19 +23,6 @@ static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d");
STATIC_DESTRUCTOR_REGISTER(arg_proc_cmdline_modules, strv_freep);
static int add_modules(const char *p) {
_cleanup_strv_free_ char **k = NULL;
k = strv_split(p, ",");
if (!k)
return log_oom();
if (strv_extend_strv(&arg_proc_cmdline_modules, k, true) < 0)
return log_oom();
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r;
@@ -44,9 +31,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (proc_cmdline_value_missing(key, value))
return 0;
r = add_modules(value);
r = strv_split_and_extend(&arg_proc_cmdline_modules, value, ",", /* filter_duplicates = */ true);
if (r < 0)
return r;
return log_error_errno(r, "Failed to parse modules_load= kernel command line option: %m");
}
return 0;

View File

@@ -5361,13 +5361,13 @@ static int make_subvolumes_strv(const Partition *p, char ***ret) {
return log_oom();
if (p->suppressing) {
_cleanup_strv_free_ char **suppressing = NULL;
char **suppressing;
r = make_subvolumes_strv(p->suppressing, &suppressing);
if (r < 0)
return r;
r = strv_extend_strv(&subvolumes, suppressing, /* filter_duplicates= */ true);
r = strv_extend_strv_consume(&subvolumes, suppressing, /* filter_duplicates= */ true);
if (r < 0)
return log_oom();
}

View File

@@ -721,13 +721,7 @@ static int extract_image_and_extensions(
e = strv_env_pairs_get(extension_release, "PORTABLE_PREFIXES");
if (e) {
_cleanup_strv_free_ char **l = NULL;
l = strv_split(e, WHITESPACE);
if (!l)
return -ENOMEM;
r = strv_extend_strv(&valid_prefixes, l, true);
r = strv_split_and_extend(&valid_prefixes, e, WHITESPACE, /* filter_duplicates = */ true);
if (r < 0)
return r;
}

View File

@@ -176,7 +176,7 @@ static int parse_path_many(
return r;
}
return strv_extend_strv(s, f, /* filter_duplicates= */ false);
return strv_extend_strv_consume(s, TAKE_PTR(f), /* filter_duplicates= */ false);
}
static int parse_tries(const char *fname, const char **p, unsigned *ret) {

View File

@@ -18,15 +18,10 @@ int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_err
}
int bus_map_strv_sort(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
_cleanup_strv_free_ char **l = NULL;
char ***p = userdata;
char ***p = ASSERT_PTR(userdata);
int r;
r = sd_bus_message_read_strv_extend(m, &l);
if (r < 0)
return bus_log_parse_error_debug(r);
r = strv_extend_strv(p, l, false);
r = sd_bus_message_read_strv_extend(m, p);
if (r < 0)
return bus_log_parse_error_debug(r);
@@ -34,10 +29,13 @@ int bus_map_strv_sort(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus
return 0;
}
static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigned flags, sd_bus_error *error, void *userdata) {
static int map_basic(sd_bus_message *m, unsigned flags, void *userdata) {
char type;
int r;
assert(m);
assert(userdata);
r = sd_bus_message_peek_type(m, &type, NULL);
if (r < 0)
return bus_log_parse_error_debug(r);
@@ -46,32 +44,29 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigne
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH: {
const char **p = userdata;
const char *s;
const char **p = userdata, *s;
r = sd_bus_message_read_basic(m, type, &s);
if (r < 0)
return bus_log_parse_error_debug(r);
if (isempty(s))
s = NULL;
s = empty_to_null(s);
if (flags & BUS_MAP_STRDUP)
return free_and_strdup((char **) userdata, s);
if (FLAGS_SET(flags, BUS_MAP_STRDUP))
return free_and_strdup((char**) p, s);
*p = s;
return 0;
}
case SD_BUS_TYPE_ARRAY: {
_cleanup_strv_free_ char **l = NULL;
char ***p = userdata;
r = sd_bus_message_read_strv_extend(m, &l);
r = sd_bus_message_read_strv_extend(m, p);
if (r < 0)
return bus_log_parse_error_debug(r);
return strv_extend_strv(p, l, false);
return 0;
}
case SD_BUS_TYPE_BOOLEAN: {
@@ -91,40 +86,39 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigne
case SD_BUS_TYPE_INT32:
case SD_BUS_TYPE_UINT32: {
uint32_t u, *p = userdata;
uint32_t *p = userdata;
r = sd_bus_message_read_basic(m, type, &u);
r = sd_bus_message_read_basic(m, type, p);
if (r < 0)
return bus_log_parse_error_debug(r);
*p = u;
return 0;
}
case SD_BUS_TYPE_INT64:
case SD_BUS_TYPE_UINT64: {
uint64_t t, *p = userdata;
uint64_t *p = userdata;
r = sd_bus_message_read_basic(m, type, &t);
r = sd_bus_message_read_basic(m, type, p);
if (r < 0)
return bus_log_parse_error_debug(r);
*p = t;
return 0;
}
case SD_BUS_TYPE_DOUBLE: {
double d, *p = userdata;
double *p = userdata;
r = sd_bus_message_read_basic(m, type, &d);
r = sd_bus_message_read_basic(m, type, p);
if (r < 0)
return bus_log_parse_error_debug(r);
*p = d;
return 0;
}}
}
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
}
int bus_message_map_all_properties(
@@ -173,7 +167,7 @@ int bus_message_map_all_properties(
if (map[i].set)
r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
else
r = map_basic(sd_bus_message_get_bus(m), member, m, flags, error, v);
r = map_basic(m, flags, v);
if (r < 0)
return bus_log_parse_error_debug(r);

View File

@@ -1343,7 +1343,7 @@ int config_parse_strv(
return log_oom();
}
r = strv_extend_strv(sv, strv, /* filter_duplicates = */ ltype);
r = strv_extend_strv_consume(sv, TAKE_PTR(strv), /* filter_duplicates = */ ltype);
if (r < 0)
return log_oom();

View File

@@ -49,25 +49,8 @@ int dlopen_libkmod(void) {
DLSYM_ARG(kmod_validate_resources));
}
static int denylist_modules(const char *p, char ***denylist) {
_cleanup_strv_free_ char **k = NULL;
int r;
assert(p);
assert(denylist);
k = strv_split(p, ",");
if (!k)
return -ENOMEM;
r = strv_extend_strv(denylist, k, /* filter_duplicates= */ true);
if (r < 0)
return r;
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
char ***denylist = ASSERT_PTR(data);
int r;
if (proc_cmdline_key_streq(key, "module_blacklist")) {
@@ -75,7 +58,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (proc_cmdline_value_missing(key, value))
return 0;
r = denylist_modules(value, data);
r = strv_split_and_extend(denylist, value, ",", /* filter_duplicates = */ true);
if (r < 0)
return r;
}

View File

@@ -208,6 +208,19 @@ static inline int run_test_table(void) {
#define DEFINE_TEST_MAIN(log_level) \
DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
#define DECIMAL_STR_FMT(x) _Generic((x), \
char: "%c", \
bool: "%d", \
unsigned char: "%d", \
short: "%hd", \
unsigned short: "%hu", \
int: "%d", \
unsigned: "%u", \
long: "%ld", \
unsigned long: "%lu", \
long long: "%lld", \
unsigned long long: "%llu")
#define ASSERT_OK(expr) \
({ \
typeof(expr) _result = (expr); \

View File

@@ -626,16 +626,15 @@ static int json_dispatch_weight(const char *name, sd_json_variant *variant, sd_j
}
int json_dispatch_user_group_list(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
char ***list = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **l = NULL;
char ***list = userdata;
sd_json_variant *e;
int r;
if (!sd_json_variant_is_array(variant))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of strings.", strna(name));
sd_json_variant *e;
JSON_VARIANT_ARRAY_FOREACH(e, variant) {
if (!sd_json_variant_is_string(e))
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
@@ -647,7 +646,7 @@ int json_dispatch_user_group_list(const char *name, sd_json_variant *variant, sd
return json_log(e, flags, r, "Failed to append array element: %m");
}
r = strv_extend_strv(list, l, true);
r = strv_extend_strv_consume(list, TAKE_PTR(l), /* filter_duplicates = */ true);
if (r < 0)
return json_log(variant, flags, r, "Failed to merge user/group arrays: %m");

View File

@@ -739,14 +739,14 @@ int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
assert(ret);
STRV_FOREACH(name, names) {
_cleanup_strv_free_ char **deps = NULL;
char **deps;
if (strv_extend(&with_deps, *name) < 0)
return log_oom();
(void) unit_get_dependencies(bus, *name, &deps);
if (strv_extend_strv(&with_deps, deps, true) < 0)
if (strv_extend_strv_consume(&with_deps, deps, /* filter_duplicates = */ true) < 0)
return log_oom();
}

View File

@@ -1771,12 +1771,13 @@ static int method_list_appstream(sd_bus_message *msg, void *userdata, sd_bus_err
return r;
HASHMAP_FOREACH(t, m->targets) {
_cleanup_strv_free_ char **target_appstream = NULL;
char **target_appstream;
r = target_get_appstream(t, &target_appstream);
if (r < 0)
return r;
r = strv_extend_strv(&urls, target_appstream, true);
r = strv_extend_strv_consume(&urls, target_appstream, /* filter_duplicates = */ true);
if (r < 0)
return r;
}

View File

@@ -660,6 +660,46 @@ TEST(strv_extend_strv) {
assert_se(strv_length(n) == 4);
}
TEST(strv_extend_strv_consume) {
_cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **n = NULL;
const char *s1, *s2, *s3;
ASSERT_NOT_NULL(a = strv_new("abc", "def", "ghi"));
ASSERT_NOT_NULL(b = strv_new("jkl", "mno", "abc", "pqr"));
s1 = b[0];
s2 = b[1];
s3 = b[3];
ASSERT_EQ(strv_extend_strv_consume(&a, TAKE_PTR(b), true), 3);
assert_se(s1 == a[3]);
assert_se(s2 == a[4]);
assert_se(s3 == a[5]);
ASSERT_STREQ(a[0], "abc");
ASSERT_STREQ(a[1], "def");
ASSERT_STREQ(a[2], "ghi");
ASSERT_STREQ(a[3], "jkl");
ASSERT_STREQ(a[4], "mno");
ASSERT_STREQ(a[5], "pqr");
ASSERT_EQ(strv_length(a), (size_t) 6);
ASSERT_NOT_NULL(c = strv_new("jkl", "mno"));
s1 = c[0];
s2 = c[1];
ASSERT_EQ(strv_extend_strv_consume(&n, TAKE_PTR(c), false), 2);
assert_se(s1 == n[0]);
assert_se(s2 == n[1]);
ASSERT_STREQ(n[0], "jkl");
ASSERT_STREQ(n[1], "mno");
ASSERT_EQ(strv_length(n), (size_t) 2);
}
TEST(strv_extend_with_size) {
_cleanup_strv_free_ char **a = NULL;
size_t n = SIZE_MAX;

View File

@@ -128,7 +128,7 @@ static int emit_deprecation_warning(void) {
NULL,
&b);
r = strv_extend_strv(&a, b, true);
r = strv_extend_strv_consume(&a, TAKE_PTR(b), /* filter_duplicates = */ true);
if (r < 0)
return r;
}

View File

@@ -1220,15 +1220,9 @@ static int parse_argv(int argc, char *argv[]) {
if (isempty(optarg))
arg_services = strv_free(arg_services);
else {
_cleanup_strv_free_ char **l = NULL;
l = strv_split(optarg, ":");
if (!l)
return log_oom();
r = strv_extend_strv(&arg_services, l, true);
r = strv_split_and_extend(&arg_services, optarg, ":", /* filter_duplicates = */ true);
if (r < 0)
return log_oom();
return log_error_errno(r, "Failed to parse -s/--service= argument: %m");
}
break;

View File

@@ -2088,14 +2088,11 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
const char *e = secure_getenv("SYSTEMD_VMSPAWN_QEMU_EXTRA");
if (e) {
_cleanup_strv_free_ char **extra = NULL;
r = strv_split_full(&extra, e, /* separator= */ NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
r = strv_split_and_extend_full(&cmdline, e,
/* separator = */ NULL, /* filter_duplicates = */ false,
EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
if (r < 0)
return log_error_errno(r, "Failed to split $SYSTEMD_VMSPAWN_QEMU_EXTRA environment variable: %m");
if (strv_extend_strv(&cmdline, extra, /* filter_duplicates= */ false) < 0)
return log_oom();
return log_error_errno(r, "Failed to parse $SYSTEMD_VMSPAWN_QEMU_EXTRA: %m");
}
if (DEBUG_LOGGING) {