diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c index fc98610a0f..96cf27dc37 100644 --- a/src/basic/alloc-util.c +++ b/src/basic/alloc-util.c @@ -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; diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index c215c33f4b..462092703a 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -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))) diff --git a/src/basic/env-util.c b/src/basic/env-util.c index cf2c47d214..4c06d1a165 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -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; } diff --git a/src/basic/macro.h b/src/basic/macro.h index 7e2bc628db..68eb7bbd0e 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -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" diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h index 2e10d33bb3..1f604cc452 100644 --- a/src/basic/memory-util.h +++ b/src/basic/memory-util.h @@ -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) { diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 0f6e0b72bf..cc6aa183c0 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -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); diff --git a/src/basic/strv.c b/src/basic/strv.c index 414123e558..a92b1234a3 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -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; diff --git a/src/basic/strv.h b/src/basic/strv.h index 1afb1bf659..49ef19dcb5 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -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) diff --git a/src/core/execute.c b/src/core/execute.c index 5e0e0b3a62..30fcffcc5b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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; diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index dc9c44e6d6..5c1ccc966f 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -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) { diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index d8fead1ca5..e49276eae5 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -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; } diff --git a/src/home/homectl.c b/src/home/homectl.c index a52bc6d464..c193715d96 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -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(); diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index e5d6547588..c2eb0db87d 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -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) { diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index a0aa12a386..007746f64f 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -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(); diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index c1f818320f..59daeb5cb0 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -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; diff --git a/src/partition/repart.c b/src/partition/repart.c index 660eef563e..1c7ac5094e 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -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(); } diff --git a/src/portable/portable.c b/src/portable/portable.c index af7d9552da..f0c508c306 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -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; } diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 50a07400fe..87aa11ccdf 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -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) { diff --git a/src/shared/bus-map-properties.c b/src/shared/bus-map-properties.c index a4833a5c1e..aa17ded5a3 100644 --- a/src/shared/bus-map-properties.c +++ b/src/shared/bus-map-properties.c @@ -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); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 39e79ef3f6..8b32f2a9bb 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -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(); diff --git a/src/shared/module-util.c b/src/shared/module-util.c index 9608b0a671..56e93e8732 100644 --- a/src/shared/module-util.c +++ b/src/shared/module-util.c @@ -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; } diff --git a/src/shared/tests.h b/src/shared/tests.h index 33180e7b37..141bfe4f22 100644 --- a/src/shared/tests.h +++ b/src/shared/tests.h @@ -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); \ diff --git a/src/shared/user-record.c b/src/shared/user-record.c index d6752f1c7b..0de768cc59 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -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"); diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c index 848012de66..0b5881ccbb 100644 --- a/src/systemctl/systemctl-util.c +++ b/src/systemctl/systemctl-util.c @@ -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(); } diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 546f52a96c..f4ff472df1 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -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; } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 7c25d59bf4..d641043c50 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -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; diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index f2b6c58b94..d47a9c3a07 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -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; } diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index 1346e2de01..5997f9604f 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -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; diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index 15418f0742..7474b301f3 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -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) {