diff options
Diffstat (limited to 'src/libsystemd/sd-bus')
-rw-r--r-- | src/libsystemd/sd-bus/bus-container.c | 11 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-dump.c | 48 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-kernel.c | 12 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-objects.c | 19 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-socket.c | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/busctl.c | 60 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/sd-bus.c | 192 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/test-bus-marshal.c | 31 |
9 files changed, 290 insertions, 87 deletions
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 5c607f49b1..435ec92d6f 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -217,15 +217,8 @@ int bus_container_connect_kernel(sd_bus *b) { _exit(EXIT_FAILURE); } - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + r = send_one_fd(pair[1], fd, 0); + if (r < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index a6b05eb88d..8833b9c677 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -73,8 +73,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64, m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() : - m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(), - ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(), + m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_normal(), + ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(), m->header->endian, m->header->flags, m->header->version, @@ -93,15 +93,15 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { fputs("\n", f); if (m->sender) - fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off()); + fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_normal()); if (m->destination) - fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off()); + fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_normal()); if (m->path) - fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off()); + fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_normal()); if (m->interface) - fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off()); + fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_normal()); if (m->member) - fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off()); + fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_normal()); if (m->sender || m->destination || m->path || m->interface || m->member) fputs("\n", f); @@ -110,8 +110,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { fprintf(f, " ErrorName=%s%s%s" " ErrorMessage=%s\"%s\"%s\n", - ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(), - ansi_highlight_red(), strna(m->error.message), ansi_highlight_off()); + ansi_highlight_red(), strna(m->error.name), ansi_normal(), + ansi_highlight_red(), strna(m->error.message), ansi_normal()); if (m->monotonic != 0) fprintf(f, " Monotonic="USEC_FMT, m->monotonic); @@ -211,55 +211,55 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { switch (type) { case SD_BUS_TYPE_BYTE: - fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off()); + fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_normal()); break; case SD_BUS_TYPE_BOOLEAN: - fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off()); + fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_normal()); break; case SD_BUS_TYPE_INT16: - fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off()); + fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_normal()); break; case SD_BUS_TYPE_UINT16: - fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off()); + fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_normal()); break; case SD_BUS_TYPE_INT32: - fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off()); + fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_normal()); break; case SD_BUS_TYPE_UINT32: - fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off()); + fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_normal()); break; case SD_BUS_TYPE_INT64: - fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off()); + fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_normal()); break; case SD_BUS_TYPE_UINT64: - fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off()); + fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_normal()); break; case SD_BUS_TYPE_DOUBLE: - fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off()); + fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_normal()); break; case SD_BUS_TYPE_STRING: - fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal()); break; case SD_BUS_TYPE_OBJECT_PATH: - fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal()); break; case SD_BUS_TYPE_SIGNATURE: - fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off()); + fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal()); break; case SD_BUS_TYPE_UNIX_FD: - fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off()); + fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_normal()); break; default: @@ -327,7 +327,7 @@ static void dump_capabilities( fputs("\n", f); if (!terse) - fputs(ansi_highlight_off(), f); + fputs(ansi_normal(), f); } int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { @@ -352,7 +352,7 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) { prefix = ""; color = ansi_highlight(); - off = ansi_highlight_off(); + off = ansi_normal(); suffix = strjoina(off, "\n"); } diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index 7af61a9433..e399701beb 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -396,6 +396,6 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); #define bus_assert_return(expr, r, error) \ do { \ - if (!assert_log(expr)) \ + if (!assert_log(expr, #expr)) \ return sd_bus_error_set_errno(error, r); \ } while (false) diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 577a8b44c3..570d35c7ad 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -1433,12 +1433,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al if (!bus || !bus->is_kernel) return -EOPNOTSUPP; - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); if (bus->n_memfd_cache <= 0) { int r; - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); r = memfd_new(bus->description); if (r < 0) @@ -1460,7 +1460,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al *allocated = c->allocated; fd = c->fd; - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); return fd; } @@ -1484,10 +1484,10 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si return; } - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); close_and_munmap(fd, address, mapped); return; @@ -1507,7 +1507,7 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si c->allocated = allocated; } - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); } void bus_kernel_flush_memfd(sd_bus *b) { diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 1d061cb9cf..728f20447a 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -1578,25 +1578,14 @@ _public_ int sd_bus_add_fallback( return bus_add_object(bus, slot, true, prefix, callback, userdata); } -static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void vtable_member_hash_func(const void *a, struct siphash *state) { const struct vtable_member *m = a; - uint8_t hash_key2[HASH_KEY_SIZE]; - unsigned long ret; assert(m); - ret = string_hash_func(m->path, hash_key); - - /* Use a slightly different hash key for the interface */ - memcpy(hash_key2, hash_key, HASH_KEY_SIZE); - hash_key2[0]++; - ret ^= string_hash_func(m->interface, hash_key2); - - /* And an even different one for the member */ - hash_key2[0]++; - ret ^= string_hash_func(m->member, hash_key2); - - return ret; + string_hash_func(m->path, state); + string_hash_func(m->interface, state); + string_hash_func(m->member, state); } static int vtable_member_compare_func(const void *a, const void *b) { diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 735a775cb4..d0b1e3d7dc 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -985,7 +985,7 @@ int bus_socket_read_message(sd_bus *bus) { return -EIO; } - f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n)); + f = realloc(bus->fds, sizeof(int) * (bus->n_fds + n)); if (!f) { close_many((int*) CMSG_DATA(cmsg), n); return -ENOMEM; diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 9a6d338231..49c97af339 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -21,22 +21,21 @@ #include <getopt.h> -#include "strv.h" -#include "util.h" -#include "log.h" -#include "build.h" -#include "pager.h" -#include "path-util.h" -#include "set.h" - #include "sd-bus.h" -#include "bus-internal.h" -#include "bus-util.h" + #include "bus-dump.h" +#include "bus-internal.h" #include "bus-signature.h" #include "bus-type.h" +#include "bus-util.h" #include "busctl-introspect.h" +#include "log.h" +#include "pager.h" +#include "path-util.h" +#include "set.h" +#include "strv.h" #include "terminal-util.h" +#include "util.h" static bool arg_no_pager = false; static bool arg_legend = true; @@ -449,7 +448,7 @@ static int tree(sd_bus *bus, char **argv) { if (not_first) printf("\n"); - printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off()); + printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); q = tree_one(bus, *i, NULL, true); if (q < 0 && r >= 0) @@ -466,7 +465,7 @@ static int tree(sd_bus *bus, char **argv) { if (argv[2]) { pager_open_if_enabled(); - printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off()); + printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); } q = tree_one(bus, *i, NULL, !!argv[2]); @@ -629,22 +628,24 @@ typedef struct Member { uint64_t flags; } Member; -static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) { +static void member_hash_func(const void *p, struct siphash *state) { const Member *m = p; - unsigned long ul; + uint64_t arity = 1; assert(m); assert(m->type); - ul = string_hash_func(m->type, hash_key); + string_hash_func(m->type, state); + + arity += !!m->name + !!m->interface; + + uint64_hash_func(&arity, state); if (m->name) - ul ^= string_hash_func(m->name, hash_key); + string_hash_func(m->name, state); if (m->interface) - ul ^= string_hash_func(m->interface, hash_key); - - return ul; + string_hash_func(m->interface, state); } static int member_compare_func(const void *a, const void *b) { @@ -1052,7 +1053,7 @@ static int introspect(sd_bus *bus, char **argv) { is_interface ? ansi_highlight() : "", is_interface ? "" : ".", - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name), - is_interface ? ansi_highlight_off() : "", + is_interface ? ansi_normal() : "", (int) type_width, strdash(m->type), (int) signature_width, strdash(m->signature), (int) result_width, rv, @@ -1096,6 +1097,15 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL if (r < 0) return log_error_errno(r, "Failed to add match: %m"); + free(m); + m = strjoin("destination='", *i, "'", NULL); + if (!m) + return log_oom(); + + r = sd_bus_add_match(bus, NULL, m, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + added_something = true; } @@ -1196,15 +1206,15 @@ static int status(sd_bus *bus, char *argv[]) { r = sd_bus_get_address(bus, &address); if (r >= 0) - printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off()); + printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal()); r = sd_bus_get_scope(bus, &scope); if (r >= 0) - printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off()); + printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal()); r = sd_bus_get_bus_id(bus, &bus_id); if (r >= 0) - printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off()); + printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal()); r = sd_bus_get_owner_creds( bus, @@ -1777,9 +1787,7 @@ static int parse_argv(int argc, char *argv[]) { return help(); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 25fd3b5c52..a23f7257fa 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -69,6 +69,10 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); static int attach_io_events(sd_bus *b); static void detach_io_events(sd_bus *b); +static thread_local sd_bus *default_system_bus = NULL; +static thread_local sd_bus *default_user_bus = NULL; +static thread_local sd_bus *default_starter_bus = NULL; + static void bus_close_fds(sd_bus *b) { assert(b); @@ -3348,14 +3352,11 @@ static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus } _public_ int sd_bus_default_system(sd_bus **ret) { - static thread_local sd_bus *default_system_bus = NULL; - return bus_default(sd_bus_open_system, &default_system_bus, ret); } -_public_ int sd_bus_default_user(sd_bus **ret) { - static thread_local sd_bus *default_user_bus = NULL; +_public_ int sd_bus_default_user(sd_bus **ret) { return bus_default(sd_bus_open_user, &default_user_bus, ret); } @@ -3382,7 +3383,6 @@ _public_ int sd_bus_default(sd_bus **ret) { e = secure_getenv("DBUS_STARTER_ADDRESS"); if (e) { - static thread_local sd_bus *default_starter_bus = NULL; return bus_default(sd_bus_open, &default_starter_bus, ret); } @@ -3454,6 +3454,171 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext return 1; } +_public_ int sd_bus_path_encode_many(char **out, const char *path_template, ...) { + _cleanup_strv_free_ char **labels = NULL; + char *path, *path_pos, **label_pos; + const char *sep, *template_pos; + size_t path_length; + va_list list; + int r; + + assert_return(out, -EINVAL); + assert_return(path_template, -EINVAL); + + path_length = strlen(path_template); + + va_start(list, path_template); + for (sep = strchr(path_template, '%'); sep; sep = strchr(sep + 1, '%')) { + const char *arg; + char *label; + + arg = va_arg(list, const char *); + if (!arg) { + va_end(list); + return -EINVAL; + } + + label = bus_label_escape(arg); + if (!label) { + va_end(list); + return -ENOMEM; + } + + r = strv_consume(&labels, label); + if (r < 0) { + va_end(list); + return r; + } + + /* add label length, but account for the format character */ + path_length += strlen(label) - 1; + } + va_end(list); + + path = malloc(path_length + 1); + if (!path) + return -ENOMEM; + + path_pos = path; + label_pos = labels; + + for (template_pos = path_template; *template_pos; ) { + sep = strchrnul(template_pos, '%'); + path_pos = mempcpy(path_pos, template_pos, sep - template_pos); + if (!*sep) + break; + + path_pos = stpcpy(path_pos, *label_pos++); + template_pos = sep + 1; + } + + *path_pos = 0; + *out = path; + return 0; +} + +_public_ int sd_bus_path_decode_many(const char *path, const char *path_template, ...) { + _cleanup_strv_free_ char **labels = NULL; + const char *template_pos, *path_pos; + char **label_pos; + va_list list; + int r; + + /* + * This decodes an object-path based on a template argument. The + * template consists of a verbatim path, optionally including special + * directives: + * + * - Each occurrence of '%' in the template matches an arbitrary + * substring of a label in the given path. At most one such + * directive is allowed per label. For each such directive, the + * caller must provide an output parameter (char **) via va_arg. If + * NULL is passed, the given label is verified, but not returned. + * For each matched label, the *decoded* label is stored in the + * passed output argument, and the caller is responsible to free + * it. Note that the output arguments are only modified if the + * actualy path matched the template. Otherwise, they're left + * untouched. + * + * This function returns <0 on error, 0 if the path does not match the + * template, 1 if it matched. + */ + + assert_return(path, -EINVAL); + assert_return(path_template, -EINVAL); + + path_pos = path; + + for (template_pos = path_template; *template_pos; ) { + const char *sep; + size_t length; + char *label; + + /* verify everything until the next '%' matches verbatim */ + sep = strchrnul(template_pos, '%'); + length = sep - template_pos; + if (strncmp(path_pos, template_pos, length)) + return 0; + + path_pos += length; + template_pos += length; + + if (!*template_pos) + break; + + /* We found the next '%' character. Everything up until here + * matched. We now skip ahead to the end of this label and make + * sure it matches the tail of the label in the path. Then we + * decode the string in-between and save it for later use. */ + + ++template_pos; /* skip over '%' */ + + sep = strchrnul(template_pos, '/'); + length = sep - template_pos; /* length of suffix to match verbatim */ + + /* verify the suffixes match */ + sep = strchrnul(path_pos, '/'); + if (sep - path_pos < (ssize_t)length || + strncmp(sep - length, template_pos, length)) + return 0; + + template_pos += length; /* skip over matched label */ + length = sep - path_pos - length; /* length of sub-label to decode */ + + /* store unescaped label for later use */ + label = bus_label_unescape_n(path_pos, length); + if (!label) + return -ENOMEM; + + r = strv_consume(&labels, label); + if (r < 0) + return r; + + path_pos = sep; /* skip decoded label and suffix */ + } + + /* end of template must match end of path */ + if (*path_pos) + return 0; + + /* copy the labels over to the caller */ + va_start(list, path_template); + for (label_pos = labels; label_pos && *label_pos; ++label_pos) { + char **arg; + + arg = va_arg(list, char **); + if (arg) + *arg = *label_pos; + else + free(*label_pos); + } + va_end(list); + + free(labels); + labels = NULL; + return 1; +} + _public_ int sd_bus_try_close(sd_bus *bus) { int r; @@ -3605,3 +3770,20 @@ _public_ int sd_bus_is_monitor(sd_bus *bus) { return !!(bus->hello_flags & KDBUS_HELLO_MONITOR); } + +static void flush_close(sd_bus *bus) { + if (!bus) + return; + + /* Flushes and closes the specified bus. We take a ref before, + * to ensure the flushing does not cause the bus to be + * unreferenced. */ + + sd_bus_flush_close_unref(sd_bus_ref(bus)); +} + +_public_ void sd_bus_default_flush_close(void) { + flush_close(default_starter_bus); + flush_close(default_user_bus); + flush_close(default_system_bus); +} diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index b203707f27..ff6bba5988 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -66,6 +66,36 @@ static void test_bus_path_encode(void) { assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar")); } +static void test_bus_path_encode_many(void) { + _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL; + + assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/prefix/bar", "/prefix/%bar", NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%/suffix", NULL) == 0); + assert_se(sd_bus_path_decode_many("/prefix/foobar/suffix", "/prefix/%/suffix", &a) == 1 && streq_ptr(a, "foobar")); + assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", &b, &c) == 1 && streq_ptr(b, "foo") && streq_ptr(c, "bar")); + assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", NULL, &d) == 1 && streq_ptr(d, "bar")); + + assert_se(sd_bus_path_decode_many("/foo/bar", "/foo/bar/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/bar", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%bar", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar/suffix") == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%%/suffix", NULL, NULL) == 0); /* multiple '%' are treated verbatim */ + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffi", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffix", &e) == 1 && streq_ptr(e, "bar")); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/%", NULL, NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/%", NULL, NULL, NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%/%/%", NULL, NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%", NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/", NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%", NULL) == 0); + + assert_se(sd_bus_path_encode_many(&f, "/prefix/one_%_two/mid/three_%_four/suffix", "foo", "bar") >= 0 && streq_ptr(f, "/prefix/one_foo_two/mid/three_bar_four/suffix")); +} + static void test_bus_label_escape_one(const char *a, const char *b) { _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL; @@ -393,6 +423,7 @@ int main(int argc, char *argv[]) { test_bus_label_escape(); test_bus_path_encode(); test_bus_path_encode_unique(); + test_bus_path_encode_many(); return 0; } |