diff options
Diffstat (limited to 'src/libsystemd/sd-bus')
61 files changed, 2033 insertions, 1231 deletions
diff --git a/src/libsystemd/sd-bus/bus-bloom.c b/src/libsystemd/sd-bus/bus-bloom.c index 91fab90cb0..112769fcb6 100644 --- a/src/libsystemd/sd-bus/bus-bloom.c +++ b/src/libsystemd/sd-bus/bus-bloom.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "siphash24.h" #include "bus-bloom.h" +#include "siphash24.h" +#include "util.h" static inline void set_bit(uint64_t filter[], unsigned long b) { filter[b >> 6] |= 1ULL << (b & 63); @@ -45,7 +43,7 @@ static void bloom_add_data( const void *data, /* Data to hash */ size_t n) { /* Size of data to hash in bytes */ - uint8_t h[8]; + uint64_t h; uint64_t m; unsigned w, i, c = 0; unsigned hash_index; @@ -72,11 +70,11 @@ static void bloom_add_data( for (d = 0; d < w; d++) { if (c <= 0) { - siphash24(h, data, n, hash_keys[hash_index++].bytes); + h = siphash24(data, n, hash_keys[hash_index++].bytes); c += 8; } - p = (p << 8ULL) | (uint64_t) h[8 - c]; + p = (p << 8ULL) | (uint64_t) ((uint8_t *)&h)[8 - c]; c--; } diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h index a9350d7f51..c824622b95 100644 --- a/src/libsystemd/sd-bus/bus-bloom.h +++ b/src/libsystemd/sd-bus/bus-bloom.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include <stdbool.h> +#include <stddef.h> #include <stdint.h> /* diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 52f8dfd3be..d2a826bf6e 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,12 +20,14 @@ #include <errno.h> #include "sd-bus.h" -#include "bus-error.h" + #include "bus-common-errors.h" +#include "bus-error.h" BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_UNIT, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_PID, ESRCH), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_EXISTS, EEXIST), SD_BUS_ERROR_MAP(BUS_ERROR_LOAD_FAILED, EIO), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_FAILED, EREMOTEIO), @@ -38,17 +38,23 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLK), - SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, EBADR), + SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, ESHUTDOWN), + SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_GENERATED, EADDRNOTAVAIL), + SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_LINKED, ELOOP), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR), SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM), SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED), SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING, EHOSTDOWN), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER, ESRCH), + SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED, EUNATCH), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_NO_MACHINE_FOR_PID, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_MACHINE_EXISTS, EEXIST), SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRIVATE_NETWORKING, ENOSYS), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_USER_MAPPING, ENXIO), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_GROUP_MAPPING, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SESSION, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SESSION_FOR_PID, ENXIO), @@ -61,17 +67,43 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_DEVICE_NOT_TAKEN, EINVAL), SD_BUS_ERROR_MAP(BUS_ERROR_OPERATION_IN_PROGRESS, EINPROGRESS), SD_BUS_ERROR_MAP(BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, EOPNOTSUPP), + SD_BUS_ERROR_MAP(BUS_ERROR_SESSION_BUSY, EBUSY), SD_BUS_ERROR_MAP(BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, EALREADY), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_PROCESS, ESRCH), - SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, EIO), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, ESRCH), SD_BUS_ERROR_MAP(BUS_ERROR_INVALID_REPLY, EINVAL), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_RR, ENOENT), - SD_BUS_ERROR_MAP(BUS_ERROR_NO_RESOURCES, ENOMEM), SD_BUS_ERROR_MAP(BUS_ERROR_CNAME_LOOP, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_ABORTED, ECANCELED), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SERVICE, EUNATCH), + SD_BUS_ERROR_MAP(BUS_ERROR_DNSSEC_FAILED, EHOSTUNREACH), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_TRUST_ANCHOR, EHOSTUNREACH), + SD_BUS_ERROR_MAP(BUS_ERROR_RR_TYPE_UNSUPPORTED, EOPNOTSUPP), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_LINK, ENXIO), + SD_BUS_ERROR_MAP(BUS_ERROR_LINK_BUSY, EBUSY), + SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_DOWN, ENETDOWN), + + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "FORMERR", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "SERVFAIL", EHOSTDOWN), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NXDOMAIN", ENXIO), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NOTIMP", ENOSYS), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "REFUSED", EACCES), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "YXDOMAIN", EEXIST), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "YRRSET", EEXIST), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NXRRSET", ENOENT), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NOTAUTH", EACCES), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "NOTZONE", EREMOTE), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADVERS", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADKEY", EKEYREJECTED), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADTIME", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADMODE", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADNAME", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADALG", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADTRUNC", EBADMSG), + SD_BUS_ERROR_MAP(_BUS_ERROR_DNS "BADCOOKIE", EBADR), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_TRANSFER, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 0dbfbddcf6..525b79fa77 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,6 +23,7 @@ #define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" #define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" +#define BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID "org.freedesktop.systemd1.NoUnitForInvocationID" #define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" #define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" #define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" @@ -36,16 +35,22 @@ #define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" #define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" #define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" +#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated" +#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked" #define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" #define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" #define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning" +#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser" +#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced" #define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" #define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage" #define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" #define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" #define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking" +#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping" +#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping" #define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" #define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" @@ -67,9 +72,15 @@ #define BUS_ERROR_NO_NAME_SERVERS "org.freedesktop.resolve1.NoNameServers" #define BUS_ERROR_INVALID_REPLY "org.freedesktop.resolve1.InvalidReply" #define BUS_ERROR_NO_SUCH_RR "org.freedesktop.resolve1.NoSuchRR" -#define BUS_ERROR_NO_RESOURCES "org.freedesktop.resolve1.NoResources" #define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop" #define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted" +#define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService" +#define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed" +#define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor" +#define BUS_ERROR_RR_TYPE_UNSUPPORTED "org.freedesktop.resolve1.ResourceRecordTypeUnsupported" +#define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink" +#define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy" +#define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown" #define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." #define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index fa7a207448..3191d27ded 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,20 +17,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <fcntl.h> +#include <unistd.h> -#include "util.h" -#include "process-util.h" +#include "bus-container.h" #include "bus-internal.h" #include "bus-socket.h" -#include "bus-container.h" +#include "fd-util.h" +#include "process-util.h" +#include "util.h" int bus_container_connect_socket(sd_bus *b) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; pid_t child; siginfo_t si; - int r; + int r, error_buf = 0; + ssize_t n; assert(b); assert(b->input_fd < 0); @@ -45,7 +46,7 @@ int bus_container_connect_socket(sd_bus *b) { return r; } - r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd); + r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); if (r < 0) return r; @@ -57,6 +58,9 @@ int bus_container_connect_socket(sd_bus *b) { bus_socket_setup(b); + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) + return -errno; + child = fork(); if (child < 0) return -errno; @@ -64,9 +68,11 @@ int bus_container_connect_socket(sd_bus *b) { if (child == 0) { pid_t grandchild; - r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); if (r < 0) - _exit(255); + _exit(EXIT_FAILURE); /* We just changed PID namespace, however it will only * take effect on the children we now fork. Hence, @@ -77,16 +83,16 @@ int bus_container_connect_socket(sd_bus *b) { grandchild = fork(); if (grandchild < 0) - _exit(255); + _exit(EXIT_FAILURE); if (grandchild == 0) { r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); if (r < 0) { - if (errno == EINPROGRESS) - _exit(1); - - _exit(255); + /* Try to send error up */ + error_buf = errno; + (void) write(pair[1], &error_buf, sizeof(error_buf)); + _exit(EXIT_FAILURE); } _exit(EXIT_SUCCESS); @@ -94,24 +100,41 @@ int bus_container_connect_socket(sd_bus *b) { r = wait_for_terminate(grandchild, &si); if (r < 0) - _exit(255); + _exit(EXIT_FAILURE); if (si.si_code != CLD_EXITED) - _exit(255); + _exit(EXIT_FAILURE); _exit(si.si_status); } + pair[1] = safe_close(pair[1]); + r = wait_for_terminate(child, &si); if (r < 0) return r; + n = read(pair[0], &error_buf, sizeof(error_buf)); + if (n < 0) + return -errno; + + if (n > 0) { + if (n != sizeof(error_buf)) + return -EIO; + + if (error_buf < 0) + return -EIO; + + if (error_buf == EINPROGRESS) + return 1; + + if (error_buf > 0) + return -error_buf; + } + if (si.si_code != CLD_EXITED) return -EIO; - if (si.si_status == 1) - return 1; - if (si.si_status != EXIT_SUCCESS) return -EIO; @@ -120,20 +143,27 @@ int bus_container_connect_socket(sd_bus *b) { int bus_container_connect_kernel(sd_bus *b) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; } control = {}; + int error_buf = 0; + struct iovec iov = { + .iov_base = &error_buf, + .iov_len = sizeof(error_buf), + }; struct msghdr mh = { .msg_control = &control, .msg_controllen = sizeof(control), + .msg_iov = &iov, + .msg_iovlen = 1, }; struct cmsghdr *cmsg; pid_t child; siginfo_t si; - int r; - _cleanup_close_ int fd = -1; + int r, fd = -1; + ssize_t n; assert(b); assert(b->input_fd < 0); @@ -146,11 +176,11 @@ int bus_container_connect_kernel(sd_bus *b) { return r; } - r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &rootfd); + r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); if (r < 0) return r; - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; child = fork(); @@ -162,7 +192,7 @@ int bus_container_connect_kernel(sd_bus *b) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); if (r < 0) _exit(EXIT_FAILURE); @@ -178,20 +208,16 @@ int bus_container_connect_kernel(sd_bus *b) { _exit(EXIT_FAILURE); if (grandchild == 0) { - fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) + if (fd < 0) { + /* Try to send error up */ + error_buf = errno; + (void) write(pair[1], &error_buf, sizeof(error_buf)); _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); @@ -213,20 +239,17 @@ int bus_container_connect_kernel(sd_bus *b) { if (r < 0) return r; - if (si.si_code != CLD_EXITED) - return -EIO; - - if (si.si_status != EXIT_SUCCESS) - return -EIO; - - if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + n = recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (n < 0) return -errno; - CMSG_FOREACH(cmsg, &mh) + CMSG_FOREACH(cmsg, &mh) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int *fds; unsigned n_fds; + assert(fd < 0); + fds = (int*) CMSG_DATA(cmsg); n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); @@ -237,9 +260,18 @@ int bus_container_connect_kernel(sd_bus *b) { fd = fds[0]; } + } + + /* If there's an fd passed, we are good. */ + if (fd >= 0) { + b->input_fd = b->output_fd = fd; + return bus_kernel_take_fd(b); + } - b->input_fd = b->output_fd = fd; - fd = -1; + /* If there's an error passed, use it */ + if (n == sizeof(error_buf) && error_buf > 0) + return -error_buf; - return bus_kernel_take_fd(b); + /* Otherwise, we have no clue */ + return -EIO; } diff --git a/src/libsystemd/sd-bus/bus-container.h b/src/libsystemd/sd-bus/bus-container.h index c6f757a99b..509ef45624 100644 --- a/src/libsystemd/sd-bus/bus-container.h +++ b/src/libsystemd/sd-bus/bus-container.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index c53666ddd0..52128e7b5c 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,17 +21,22 @@ #include <valgrind/memcheck.h> #endif -#include <stddef.h> #include <errno.h> +#include <stddef.h> -#include "strv.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-bloom.h" +#include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-control.h" -#include "bus-bloom.h" #include "bus-util.h" -#include "capability.h" +#include "capability-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { int r; @@ -86,7 +89,7 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags } static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret, param = 0; int r; @@ -182,7 +185,7 @@ static int bus_release_name_kernel(sd_bus *bus, const char *name) { } static int bus_release_name_dbus1(sd_bus *bus, const char *name) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret; int r; @@ -256,11 +259,9 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); KDBUS_FOREACH(name, name_list, cmd.list_size) { - struct kdbus_item *item; - const char *entry_name = NULL; - if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id) { + if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) { char *n; if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) { @@ -275,15 +276,15 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) { previous_id = name->id; } - KDBUS_ITEM_FOREACH(item, name, items) - if (item->type == KDBUS_ITEM_OWNED_NAME) - entry_name = item->name.name; - - if (entry_name && service_name_is_valid(entry_name)) { - r = strv_extend(x, entry_name); - if (r < 0) { - r = -ENOMEM; - goto fail; + KDBUS_ITEM_FOREACH(item, name, items) { + if (item->type == KDBUS_ITEM_OWNED_NAME) { + if (service_name_is_valid(item->name.name)) { + r = strv_extend(x, item->name.name); + if (r < 0) { + r = -ENOMEM; + goto fail; + } + } } } } @@ -323,7 +324,7 @@ static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activata } static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **x = NULL, **y = NULL; int r; @@ -644,7 +645,7 @@ int bus_get_name_creds_kdbus( bool allow_activator, sd_bus_creds **creds) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; struct kdbus_cmd_info *cmd; struct kdbus_info *conn_info; size_t size, l; @@ -677,6 +678,7 @@ int bus_get_name_creds_kdbus( (mask & (SD_BUS_CREDS_PPID| SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| + SD_BUS_CREDS_SUPPLEMENTARY_GIDS| SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| @@ -750,8 +752,8 @@ static int bus_get_name_creds_dbus1( uint64_t mask, sd_bus_creds **creds) { - _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL; - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; const char *unique = NULL; pid_t pid = 0; int r; @@ -794,6 +796,7 @@ static int bus_get_name_creds_dbus1( ((mask & SD_BUS_CREDS_AUGMENT) && (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| + SD_BUS_CREDS_SUPPLEMENTARY_GIDS| SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| @@ -855,7 +858,7 @@ static int bus_get_name_creds_dbus1( } if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const void *p = NULL; size_t sz = 0; @@ -927,7 +930,7 @@ _public_ int sd_bus_get_name_creds( } static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; struct kdbus_cmd_info cmd = { .size = sizeof(struct kdbus_cmd_info), }; @@ -946,6 +949,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** (mask & (SD_BUS_CREDS_PPID| SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID| + SD_BUS_CREDS_SUPPLEMENTARY_GIDS| SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID| SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS| @@ -976,10 +980,14 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** } static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; pid_t pid = 0; + bool do_label; int r; - bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); + + assert(bus); + + do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); /* Avoid allocating anything if we have no chance of returning useful data */ if (!bus->ucred_valid && !do_label) @@ -1126,8 +1134,7 @@ static int add_name_change_match(sd_bus *bus, item->name_change.old_id.id = old_owner_id; item->name_change.new_id.id = new_owner_id; - if (name) - memcpy(item->name_change.name, name, l); + memcpy_safe(item->name_change.name, name, l); /* If the old name is unset or empty, then * this can match against added names */ @@ -1311,7 +1318,16 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: { + case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: { + char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; + + xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS); + bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str); + using_bloom = true; + break; + } + + case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: /* * XXX: DBus spec defines arg[0..63]path= matching to be * a two-way glob. That is, if either string is a prefix @@ -1325,7 +1341,6 @@ int bus_add_match_internal_kernel( * to properly support multiple-matches here. */ break; - } case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: { char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")]; @@ -1336,7 +1351,7 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_DESTINATION: { + case BUS_MATCH_DESTINATION: /* * Kernel only supports matching on destination IDs, but * not on destination names. So just skip the @@ -1354,7 +1369,6 @@ int bus_add_match_internal_kernel( matches_name_change = false; break; - } case BUS_MATCH_ROOT: case BUS_MATCH_VALUE: @@ -1529,7 +1543,7 @@ int bus_remove_match_internal( } _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; const char *mid; int r; diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h index 5009ca8e61..c181aa7959 100644 --- a/src/libsystemd/sd-bus/bus-control.h +++ b/src/libsystemd/sd-bus/bus-control.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "bus-match.h" int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie); diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index dfd82e746d..2d06bf541f 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,8 +20,9 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-signature.h" -#include "bus-util.h" #include "bus-type.h" +#include "bus-util.h" +#include "string-util.h" _public_ int sd_bus_emit_signal( sd_bus *bus, @@ -32,7 +31,7 @@ _public_ int sd_bus_emit_signal( const char *member, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(bus, -EINVAL); @@ -69,7 +68,7 @@ _public_ int sd_bus_call_method_async( void *userdata, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(bus, -EINVAL); @@ -105,18 +104,20 @@ _public_ int sd_bus_call_method( sd_bus_message **reply, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member); if (r < 0) - return r; + goto fail; if (!isempty(types)) { va_list ap; @@ -125,17 +126,20 @@ _public_ int sd_bus_call_method( r = bus_message_append_ap(m, types, ap); va_end(ap); if (r < 0) - return r; + goto fail; } return sd_bus_call(bus, m, 0, error, reply); + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_reply_method_return( sd_bus_message *call, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(call, -EINVAL); @@ -171,7 +175,7 @@ _public_ int sd_bus_reply_method_error( sd_bus_message *call, const sd_bus_error *e) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(call, -EINVAL); @@ -200,7 +204,7 @@ _public_ int sd_bus_reply_method_errorf( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; assert_return(call, -EINVAL); @@ -227,7 +231,7 @@ _public_ int sd_bus_reply_method_errno( int error, const sd_bus_error *p) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); @@ -255,7 +259,7 @@ _public_ int sd_bus_reply_method_errnof( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; va_list ap; assert_return(call, -EINVAL); @@ -290,15 +294,17 @@ _public_ int sd_bus_get_property( sd_bus_message *rep = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(reply, -EINVAL); - assert_return(signature_is_single(type, false), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(reply, -EINVAL, error); + bus_assert_return(signature_is_single(type, false), -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member); if (r < 0) @@ -307,11 +313,14 @@ _public_ int sd_bus_get_property( r = sd_bus_message_enter_container(rep, 'v', type); if (r < 0) { sd_bus_message_unref(rep); - return r; + goto fail; } *reply = rep; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_trivial( @@ -323,18 +332,20 @@ _public_ int sd_bus_get_property_trivial( sd_bus_error *error, char type, void *ptr) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(bus_type_is_trivial(type), -EINVAL); - assert_return(ptr, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(bus_type_is_trivial(type), -EINVAL, error); + bus_assert_return(ptr, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -342,13 +353,16 @@ _public_ int sd_bus_get_property_trivial( r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type)); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_basic(reply, type, ptr); if (r < 0) - return r; + goto fail; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_string( @@ -360,19 +374,21 @@ _public_ int sd_bus_get_property_string( sd_bus_error *error, char **ret) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *s; char *n; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(ret, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -380,18 +396,23 @@ _public_ int sd_bus_get_property_string( r = sd_bus_message_enter_container(reply, 'v', "s"); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_basic(reply, 's', &s); if (r < 0) - return r; + goto fail; n = strdup(s); - if (!n) - return -ENOMEM; + if (!n) { + r = -ENOMEM; + goto fail; + } *ret = n; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_property_strv( @@ -403,17 +424,19 @@ _public_ int sd_bus_get_property_strv( sd_bus_error *error, char ***ret) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(ret, -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(ret, -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member); if (r < 0) @@ -421,13 +444,16 @@ _public_ int sd_bus_get_property_strv( r = sd_bus_message_enter_container(reply, 'v', NULL); if (r < 0) - return r; + goto fail; r = sd_bus_message_read_strv(reply, ret); if (r < 0) - return r; + goto fail; return 0; + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_set_property( @@ -439,42 +465,47 @@ _public_ int sd_bus_set_property( sd_bus_error *error, const char *type, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; va_list ap; int r; - assert_return(bus, -EINVAL); - assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL); - assert_return(member_name_is_valid(member), -EINVAL); - assert_return(signature_is_single(type, false), -EINVAL); - assert_return(!bus_pid_changed(bus), -ECHILD); + bus_assert_return(bus, -EINVAL, error); + bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error); + bus_assert_return(member_name_is_valid(member), -EINVAL, error); + bus_assert_return(signature_is_single(type, false), -EINVAL, error); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set"); if (r < 0) - return r; + goto fail; r = sd_bus_message_append(m, "ss", strempty(interface), member); if (r < 0) - return r; + goto fail; r = sd_bus_message_open_container(m, 'v', type); if (r < 0) - return r; + goto fail; va_start(ap, type); r = bus_message_append_ap(m, type, ap); va_end(ap); if (r < 0) - return r; + goto fail; r = sd_bus_message_close_container(m); if (r < 0) - return r; + goto fail; return sd_bus_call(bus, m, 0, error, NULL); + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) { @@ -522,7 +553,7 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b } _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; uid_t our_uid; bool know_caps = false; int r; diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 1c365b7fcd..c4f693dee9 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,22 +17,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <linux/capability.h> +#include <stdlib.h> -#include "util.h" -#include "formats-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "capability.h" -#include "cgroup-util.h" -#include "fileio.h" -#include "audit.h" +#include "alloc-util.h" +#include "audit-util.h" +#include "bus-creds.h" +#include "bus-label.h" #include "bus-message.h" #include "bus-util.h" +#include "capability-util.h" +#include "cgroup-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" #include "strv.h" -#include "bus-creds.h" -#include "bus-label.h" +#include "terminal-util.h" +#include "user-util.h" +#include "util.h" enum { CAP_OFFSET_INHERITABLE = 0, @@ -69,7 +73,9 @@ void bus_creds_done(sd_bus_creds *c) { } _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) { - assert_return(c, NULL); + + if (!c) + return NULL; if (c->allocated) { assert(c->n_ref > 0); @@ -107,11 +113,9 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) { free(c->cgroup_root); free(c->description); - free(c->supplementary_gids); - c->supplementary_gids = NULL; + c->supplementary_gids = mfree(c->supplementary_gids); - strv_free(c->well_known_names); - c->well_known_names = NULL; + c->well_known_names = strv_free(c->well_known_names); bus_creds_done(c); @@ -1015,10 +1019,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (r != -EPERM && r != -EACCES) return r; } else { - if (c->cmdline_size == 0) { - free(c->cmdline); - c->cmdline = NULL; - } + if (c->cmdline_size == 0) + c->cmdline = mfree(c->cmdline); c->mask |= SD_BUS_CREDS_CMDLINE; } @@ -1062,8 +1064,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) { r = audit_session_from_pid(pid, &c->audit_session_id); - if (r == -ENXIO) { - /* ENXIO means: no audit session id assigned */ + if (r == -ENODATA) { + /* ENODATA means: no audit session id assigned */ c->audit_session_id = AUDIT_SESSION_INVALID; c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID; } else if (r < 0) { @@ -1075,8 +1077,8 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) { r = audit_loginuid_from_pid(pid, &c->audit_login_uid); - if (r == -ENXIO) { - /* ENXIO means: no audit login uid assigned */ + if (r == -ENODATA) { + /* ENODATA means: no audit login uid assigned */ c->audit_login_uid = UID_INVALID; c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID; } else if (r < 0) { @@ -1116,7 +1118,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { } int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *n = NULL; int r; assert(c); diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h index 209d216123..df8a1f1005 100644 --- a/src/libsystemd/sd-bus/bus-creds.h +++ b/src/libsystemd/sd-bus/bus-creds.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 9db86adb7f..21a6b20a11 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,18 +17,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "capability.h" -#include "strv.h" -#include "macro.h" +#include "alloc-util.h" +#include "bus-dump.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-type.h" #include "cap-list.h" +#include "capability-util.h" +#include "fileio.h" #include "formats-util.h" +#include "locale-util.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" - -#include "bus-message.h" -#include "bus-internal.h" -#include "bus-type.h" -#include "bus-dump.h" +#include "util.h" static char *indent(unsigned level, unsigned flags) { char *p; @@ -73,8 +74,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() : "", special_glyph(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 +94,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 +111,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); @@ -197,7 +198,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { else if (type == SD_BUS_TYPE_DICT_ENTRY) fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents); - level ++; + level++; continue; } @@ -211,55 +212,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 +328,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 +353,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"); } @@ -551,9 +552,8 @@ int bus_pcap_header(size_t snaplen, FILE *f) { hdr.snaplen = (uint32_t) snaplen; fwrite(&hdr, 1, sizeof(hdr), f); - fflush(f); - return 0; + return fflush_and_check(f); } int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) { @@ -598,7 +598,5 @@ int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) { snaplen -= w; } - fflush(f); - - return 0; + return fflush_and_check(f); } diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h index d2522edeba..874e86d09c 100644 --- a/src/libsystemd/sd-bus/bus-dump.h +++ b/src/libsystemd/sd-bus/bus-dump.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> #include "sd-bus.h" diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c index dac157be16..378f7a377a 100644 --- a/src/libsystemd/sd-bus/bus-error.c +++ b/src/libsystemd/sd-bus/bus-error.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,17 +18,19 @@ ***/ #include <errno.h> -#include <stdlib.h> #include <stdarg.h> #include <stdbool.h> -#include <string.h> #include <stdio.h> - -#include "util.h" -#include "errno-list.h" +#include <stdlib.h> +#include <string.h> #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-error.h" +#include "errno-list.h" +#include "string-util.h" +#include "util.h" BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = { SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES), @@ -89,14 +89,14 @@ static int bus_error_name_to_errno(const char *name) { p = startswith(name, "System.Error."); if (p) { r = errno_from_name(p); - if (r <= 0) + if (r < 0) return EIO; return r; } - if (additional_error_maps) { - for (map = additional_error_maps; *map; map++) { + if (additional_error_maps) + for (map = additional_error_maps; *map; map++) for (m = *map;; m++) { /* For additional error maps the end marker is actually the end marker */ if (m->code == BUS_ERROR_MAP_END_MARKER) @@ -105,15 +105,13 @@ static int bus_error_name_to_errno(const char *name) { if (streq(m->name, name)) return m->code; } - } - } m = __start_BUS_ERROR_MAP; while (m < __stop_BUS_ERROR_MAP) { /* For magic ELF error maps, the end marker might * appear in the middle of things, since multiple maps * might appear in the same section. Hence, let's skip - * over it, but realign the pointer to the netx 8byte + * over it, but realign the pointer to the next 8 byte * boundary, which is the selected alignment for the * arrays. */ if (m->code == BUS_ERROR_MAP_END_MARKER) { @@ -254,25 +252,24 @@ int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_li if (!name) return 0; - if (!e) - goto finish; - assert_return(!bus_error_is_dirty(e), -EINVAL); + if (e) { + assert_return(!bus_error_is_dirty(e), -EINVAL); - e->name = strdup(name); - if (!e->name) { - *e = BUS_ERROR_OOM; - return -ENOMEM; - } + e->name = strdup(name); + if (!e->name) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } - /* If we hit OOM on formatting the pretty message, we ignore - * this, since we at least managed to write the error name */ - if (format) - (void) vasprintf((char**) &e->message, format, ap); + /* If we hit OOM on formatting the pretty message, we ignore + * this, since we at least managed to write the error name */ + if (format) + (void) vasprintf((char**) &e->message, format, ap); - e->_need_free = 1; + e->_need_free = 1; + } -finish: return -bus_error_name_to_errno(name); } @@ -563,7 +560,7 @@ _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *for const char *bus_error_message(const sd_bus_error *e, int error) { if (e) { - /* Sometimes the D-Bus server is a little bit too verbose with + /* Sometimes, the D-Bus server is a little bit too verbose with * its error messages, so let's override them here */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED)) return "Access denied"; @@ -578,27 +575,29 @@ const char *bus_error_message(const sd_bus_error *e, int error) { return strerror(error); } +static bool map_ok(const sd_bus_error_map *map) { + for (; map->code != BUS_ERROR_MAP_END_MARKER; map++) + if (!map->name || map->code <=0) + return false; + return true; +} + _public_ int sd_bus_error_add_map(const sd_bus_error_map *map) { const sd_bus_error_map **maps = NULL; unsigned n = 0; assert_return(map, -EINVAL); + assert_return(map_ok(map), -EINVAL); - if (additional_error_maps) { - for (;; n++) { - if (additional_error_maps[n] == NULL) - break; - + if (additional_error_maps) + for (; additional_error_maps[n] != NULL; n++) if (additional_error_maps[n] == map) return 0; - } - } maps = realloc_multiply(additional_error_maps, sizeof(struct sd_bus_error_map*), n + 2); if (!maps) return -ENOMEM; - maps[n] = map; maps[n+1] = NULL; diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h index fb0199c948..e2c4cf4b3f 100644 --- a/src/libsystemd/sd-bus/bus-error.h +++ b/src/libsystemd/sd-bus/bus-error.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,6 +22,7 @@ #include <stdbool.h> #include "sd-bus.h" + #include "macro.h" bool bus_error_is_dirty(sd_bus_error *e); diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c index 2d18a4e6c1..58782767fa 100644 --- a/src/libsystemd/sd-bus/bus-gvariant.c +++ b/src/libsystemd/sd-bus/bus-gvariant.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "bus-type.h" #include "bus-gvariant.h" #include "bus-signature.h" +#include "bus-type.h" int bus_gvariant_get_size(const char *signature) { const char *p; @@ -75,14 +73,19 @@ int bus_gvariant_get_size(const char *signature) { case SD_BUS_TYPE_STRUCT_BEGIN: case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { - char t[n-1]; - - memcpy(t, p + 1, n - 2); - t[n - 2] = 0; - - r = bus_gvariant_get_size(t); - if (r < 0) - return r; + if (n == 2) { + /* unary type () has fixed size of 1 */ + r = 1; + } else { + char t[n-1]; + + memcpy(t, p + 1, n - 2); + t[n - 2] = 0; + + r = bus_gvariant_get_size(t); + if (r < 0) + return r; + } sum += r; break; diff --git a/src/libsystemd/sd-bus/bus-gvariant.h b/src/libsystemd/sd-bus/bus-gvariant.h index 875d34b59b..6da637fb05 100644 --- a/src/libsystemd/sd-bus/bus-gvariant.h +++ b/src/libsystemd/sd-bus/bus-gvariant.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c index fea796cd30..caca679086 100644 --- a/src/libsystemd/sd-bus/bus-internal.c +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "bus-message.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-message.h" +#include "hexdecoct.h" +#include "string-util.h" bool object_path_is_valid(const char *p) { const char *q; diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index c3e20ee1bf..bb0414c4d6 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,21 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <pthread.h> - -#include "hashmap.h" -#include "prioq.h" -#include "list.h" -#include "util.h" -#include "refcnt.h" -#include "socket-util.h" +#include <sys/socket.h> #include "sd-bus.h" + #include "bus-error.h" -#include "bus-match.h" #include "bus-kernel.h" +#include "bus-match.h" +#include "hashmap.h" #include "kdbus.h" +#include "list.h" +#include "prioq.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" struct reply_callback { sd_bus_message_handler_t callback; @@ -211,6 +209,9 @@ struct sd_bus { bool is_system:1; bool is_user:1; bool allow_interactive_authorization:1; + bool exit_on_disconnect:1; + bool exited:1; + bool exit_triggered:1; int use_memfd; @@ -322,12 +323,13 @@ struct sd_bus { sd_bus_track *track_queue; LIST_HEAD(sd_bus_slot, slots); + LIST_HEAD(sd_bus_track, tracks); }; #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) -#define BUS_WQUEUE_MAX 1024 -#define BUS_RQUEUE_MAX 64*1024 +#define BUS_WQUEUE_MAX (192*1024) +#define BUS_RQUEUE_MAX (192*1024) #define BUS_MESSAGE_SIZE_MAX (64*1024*1024) #define BUS_AUTH_SIZE_MAX (64*1024) @@ -381,7 +383,7 @@ char *bus_address_escape(const char *v); * bus from the callback doesn't destroy the object we are working * on */ #define BUS_DONT_DESTROY(bus) \ - _cleanup_bus_unref_ _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus) + _cleanup_(sd_bus_unrefp) _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus) int bus_set_address_system(sd_bus *bus); int bus_set_address_user(sd_bus *bus); @@ -393,3 +395,9 @@ int bus_remove_match_by_string(sd_bus *bus, const char *match, sd_bus_message_ha int bus_get_root_path(sd_bus *bus); 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, #expr)) \ + return sd_bus_error_set_errno(error, r); \ + } while (false) diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c index e2f4550c7e..8f93edb8da 100644 --- a/src/libsystemd/sd-bus/bus-introspect.c +++ b/src/libsystemd/sd-bus/bus-introspect.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "bus-introspect.h" -#include "bus-signature.h" #include "bus-internal.h" +#include "bus-introspect.h" #include "bus-protocol.h" +#include "bus-signature.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "util.h" int introspect_begin(struct introspect *i, bool trusted) { assert(i); @@ -81,6 +82,9 @@ static void introspect_write_flags(struct introspect *i, int type, int flags) { fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f); if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) { + if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) + fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f); + if (flags & SD_BUS_VTABLE_PROPERTY_CONST) fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f); else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) @@ -179,10 +183,10 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b assert(reply); fputs("</node>\n", i->f); - fflush(i->f); - if (ferror(i->f)) - return -ENOMEM; + r = fflush_and_check(i->f); + if (r < 0) + return r; r = sd_bus_message_new_method_return(m, &q); if (r < 0) @@ -201,11 +205,8 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b void introspect_free(struct introspect *i) { assert(i); - if (i->f) - fclose(i->f); - - if (i->introspection) - free(i->introspection); + safe_fclose(i->f); + free(i->introspection); zero(*i); } diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h index 1914e6cb8b..8e2f3800ca 100644 --- a/src/libsystemd/sd-bus/bus-introspect.h +++ b/src/libsystemd/sd-bus/bus-introspect.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,6 +22,7 @@ #include <stdio.h> #include "sd-bus.h" + #include "set.h" struct introspect { diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index e3fac01f92..59398b841d 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -34,19 +32,24 @@ #include <libgen.h> #undef basename -#include "util.h" -#include "strv.h" -#include "memfd-util.h" -#include "capability.h" -#include "fileio.h" -#include "formats-util.h" - +#include "alloc-util.h" +#include "bus-bloom.h" #include "bus-internal.h" -#include "bus-message.h" #include "bus-kernel.h" -#include "bus-bloom.h" -#include "bus-util.h" #include "bus-label.h" +#include "bus-message.h" +#include "bus-util.h" +#include "capability-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "memfd-util.h" +#include "parse-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) @@ -168,6 +171,27 @@ static void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, bloom_add_prefixes(data, size, n_hash, buf, t, '/'); } +static void add_bloom_arg_has(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) { + char buf[sizeof("arg")-1 + 2 + sizeof("-has")]; + char *e; + + assert(data); + assert(size > 0); + assert(i < 64); + assert(t); + + e = stpcpy(buf, "arg"); + if (i < 10) + *(e++) = '0' + (char) i; + else { + *(e++) = '0' + (char) (i / 10); + *(e++) = '0' + (char) (i % 10); + } + + strcpy(e, "-has"); + bloom_add_pair(data, size, n_hash, buf, t); +} + static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) { void *data; unsigned i; @@ -212,7 +236,9 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter return r; add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); - } if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) { + } + + if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) { /* As well as array of simple strings of any kinds */ r = sd_bus_message_enter_container(m, type, contents); @@ -220,7 +246,7 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter return r; while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0) - add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); + add_bloom_arg_has(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t); if (r < 0) return r; @@ -242,8 +268,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { struct bus_body_part *part; struct kdbus_item *d; const char *destination; - bool well_known; - uint64_t unique; + bool well_known = false; + uint64_t dst_id; size_t sz, dl; unsigned i; int r; @@ -260,13 +286,21 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { destination = m->destination ?: m->destination_ptr; if (destination) { - r = bus_kernel_parse_unique_name(destination, &unique); + r = bus_kernel_parse_unique_name(destination, &dst_id); if (r < 0) return r; - - well_known = r == 0; + if (r == 0) { + well_known = true; + + /* verify_destination_id will usually be 0, which makes the kernel + * driver only look at the provided well-known name. Otherwise, + * the kernel will make sure the provided destination id matches + * the owner of the provided well-known-name, and fail if they + * differ. Currently, this is only needed for bus-proxyd. */ + dst_id = m->verify_destination_id; + } } else - well_known = false; + dst_id = KDBUS_DST_ID_BROADCAST; sz = offsetof(struct kdbus_msg, items); @@ -304,15 +338,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0) | ((m->header->type == SD_BUS_MESSAGE_SIGNAL) ? KDBUS_MSG_SIGNAL : 0); - if (well_known) - /* verify_destination_id will usually be 0, which makes the kernel driver only look - * at the provided well-known name. Otherwise, the kernel will make sure the provided - * destination id matches the owner of the provided weel-known-name, and fail if they - * differ. Currently, this is only needed for bus-proxyd. */ - m->kdbus->dst_id = m->verify_destination_id; - else - m->kdbus->dst_id = destination ? unique : KDBUS_DST_ID_BROADCAST; - + m->kdbus->dst_id = dst_id; m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS; m->kdbus->cookie = m->header->dbus2.cookie; m->kdbus->priority = m->priority; @@ -774,6 +800,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { case KDBUS_ITEM_FDS: case KDBUS_ITEM_SECLABEL: + case KDBUS_ITEM_BLOOM_FILTER: break; default: @@ -821,7 +848,8 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { if (k->src_id == KDBUS_SRC_ID_KERNEL) bus_message_set_sender_driver(bus, m); else { - snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id); + xsprintf(m->sender_buffer, ":1.%llu", + (unsigned long long)k->src_id); m->sender = m->creds.unique_name = m->sender_buffer; } @@ -832,7 +860,8 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { else if (k->dst_id == KDBUS_DST_ID_NAME) m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */ else { - snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id); + xsprintf(m->destination_buffer, ":1.%llu", + (unsigned long long)k->dst_id); m->destination = m->destination_buffer; } @@ -1114,7 +1143,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call r = ioctl(bus->output_fd, KDBUS_CMD_SEND, &cmd); if (r < 0) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus_message *reply; if (errno == EAGAIN || errno == EINTR) @@ -1193,7 +1222,7 @@ static int push_name_owner_changed( const char *new_owner, const struct kdbus_timestamp *ts) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -1280,7 +1309,7 @@ static int translate_reply( const struct kdbus_item *d, const struct kdbus_timestamp *ts) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -1332,8 +1361,7 @@ static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) { KDBUS_ITEM_FOREACH(d, k, items) { if (d->type == KDBUS_ITEM_TIMESTAMP) ts = &d->timestamp; - - if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) { + else if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) { if (found) return -EBADMSG; found = d; @@ -1410,12 +1438,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) @@ -1437,7 +1465,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; } @@ -1461,10 +1489,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; @@ -1484,7 +1512,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) { @@ -1665,50 +1693,6 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) { return fd; } -int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) { - _cleanup_free_ char *path = NULL; - struct kdbus_cmd *make; - struct kdbus_item *n; - const char *name; - int fd; - - fd = bus_kernel_open_bus_fd(bus_name, &path); - if (fd < 0) - return fd; - - make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd, items)) + - ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + strlen(ep_name) + 1), - 8); - make->size = ALIGN8(offsetof(struct kdbus_cmd, items)); - make->flags = KDBUS_MAKE_ACCESS_WORLD; - - n = make->items; - sprintf(n->str, UID_FMT "-%s", getuid(), ep_name); - n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1; - n->type = KDBUS_ITEM_MAKE_NAME; - make->size += ALIGN8(n->size); - name = n->str; - - if (ioctl(fd, KDBUS_CMD_ENDPOINT_MAKE, make) < 0) { - safe_close(fd); - return -errno; - } - - if (ep_path) { - char *p; - - p = strjoin(dirname(path), "/", name, NULL); - if (!p) { - safe_close(fd); - return -ENOMEM; - } - - *ep_path = p; - } - - return fd; -} - int bus_kernel_try_close(sd_bus *bus) { struct kdbus_cmd byebye = { .size = sizeof(byebye) }; diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h index bb4dff6d82..53ba3bdcf3 100644 --- a/src/libsystemd/sd-bus/bus-kernel.h +++ b/src/libsystemd/sd-bus/bus-kernel.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 132b37526e..db01f21135 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-internal.h" -#include "bus-message.h" #include "bus-match.h" +#include "bus-message.h" #include "bus-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "string-util.h" #include "strv.h" /* Example: @@ -62,12 +65,13 @@ */ static inline bool BUS_MATCH_IS_COMPARE(enum bus_match_node_type t) { - return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_NAMESPACE_LAST; + return t >= BUS_MATCH_SENDER && t <= BUS_MATCH_ARG_HAS_LAST; } static inline bool BUS_MATCH_CAN_HASH(enum bus_match_node_type t) { return (t >= BUS_MATCH_MESSAGE_TYPE && t <= BUS_MATCH_PATH) || - (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST); + (t >= BUS_MATCH_ARG && t <= BUS_MATCH_ARG_LAST) || + (t >= BUS_MATCH_ARG_HAS && t <= BUS_MATCH_ARG_HAS_LAST); } static void bus_match_node_free(struct bus_match_node *node) { @@ -179,12 +183,16 @@ static bool value_node_test( case BUS_MATCH_INTERFACE: case BUS_MATCH_MEMBER: case BUS_MATCH_PATH: - case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: { - char **i; + case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: if (value_str) return streq_ptr(node->value.str, value_str); + return false; + + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: { + char **i; + STRV_FOREACH(i, value_strv) if (streq_ptr(node->value.str, *i)) return true; @@ -192,33 +200,20 @@ static bool value_node_test( return false; } - case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: { - char **i; - + case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: if (value_str) return namespace_simple_pattern(node->value.str, value_str); - STRV_FOREACH(i, value_strv) - if (namespace_simple_pattern(node->value.str, *i)) - return true; return false; - } case BUS_MATCH_PATH_NAMESPACE: return path_simple_pattern(node->value.str, value_str); - case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: { - char **i; - + case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: if (value_str) return path_complex_pattern(node->value.str, value_str); - STRV_FOREACH(i, value_strv) - if (path_complex_pattern(node->value.str, *i)) - return true; - return false; - } default: assert_not_reached("Invalid node type"); @@ -249,6 +244,7 @@ static bool value_node_same( case BUS_MATCH_MEMBER: case BUS_MATCH_PATH: case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: case BUS_MATCH_PATH_NAMESPACE: case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: @@ -319,7 +315,7 @@ int bus_match_run( /* Run the callback. And then invoke siblings. */ if (node->leaf.callback->callback) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; sd_bus_slot *slot; slot = container_of(node->leaf.callback, sd_bus_slot, match_callback); @@ -372,15 +368,19 @@ int bus_match_run( break; case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: - (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv); + (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str); break; case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: - (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv); + (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str); break; case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: - (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv); + (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str); + break; + + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: + (void) bus_message_get_arg_strv(m, node->type - BUS_MATCH_ARG_HAS, &test_strv); break; default: @@ -429,6 +429,9 @@ int bus_match_run( r = bus_match_run(bus, c, m); if (r != 0) return r; + + if (bus && bus->match_callbacks_modified) + return 0; } } @@ -743,6 +746,32 @@ enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n return t; } + if (n == 7 && startswith(k, "arg") && startswith(k + 4, "has")) { + int j; + + j = undecchar(k[3]); + if (j < 0) + return -EINVAL; + + return BUS_MATCH_ARG_HAS + j; + } + + if (n == 8 && startswith(k, "arg") && startswith(k + 5, "has")) { + enum bus_match_node_type t; + int a, b; + + a = undecchar(k[3]); + b = undecchar(k[4]); + if (a <= 0 || b < 0) + return -EINVAL; + + t = BUS_MATCH_ARG_HAS + a * 10 + b; + if (t > BUS_MATCH_ARG_HAS_LAST) + return -EINVAL; + + return t; + } + return -EINVAL; } @@ -861,8 +890,7 @@ int bus_match_parse( if (r < 0) goto fail; - free(value); - value = NULL; + value = mfree(value); } else u = 0; @@ -910,10 +938,11 @@ fail: } char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) { - _cleanup_free_ FILE *f = NULL; + _cleanup_fclose_ FILE *f = NULL; char *buffer = NULL; size_t size = 0; unsigned i; + int r; if (n_components <= 0) return strdup(""); @@ -942,8 +971,8 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com fputc('\'', f); } - fflush(f); - if (ferror(f)) + r = fflush_and_check(f); + if (r < 0) return NULL; return buffer; @@ -1111,6 +1140,10 @@ const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[] snprintf(buf, l, "arg%inamespace", t - BUS_MATCH_ARG_NAMESPACE); return buf; + case BUS_MATCH_ARG_HAS ... BUS_MATCH_ARG_HAS_LAST: + snprintf(buf, l, "arg%ihas", t - BUS_MATCH_ARG_HAS); + return buf; + default: return NULL; } diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index 56516be9fa..8cbbb63b11 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "hashmap.h" - #include "sd-bus.h" +#include "hashmap.h" + enum bus_match_node_type { BUS_MATCH_ROOT, BUS_MATCH_VALUE, @@ -44,6 +42,8 @@ enum bus_match_node_type { BUS_MATCH_ARG_PATH_LAST = BUS_MATCH_ARG_PATH + 63, BUS_MATCH_ARG_NAMESPACE, BUS_MATCH_ARG_NAMESPACE_LAST = BUS_MATCH_ARG_NAMESPACE + 63, + BUS_MATCH_ARG_HAS, + BUS_MATCH_ARG_HAS_LAST = BUS_MATCH_ARG_HAS + 63, _BUS_MATCH_NODE_TYPE_MAX, _BUS_MATCH_NODE_TYPE_INVALID = -1 }; diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 18685be8ff..5cec804e32 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,19 +21,23 @@ #include <fcntl.h> #include <sys/mman.h> -#include "util.h" -#include "utf8.h" -#include "strv.h" -#include "time-util.h" -#include "memfd-util.h" - #include "sd-bus.h" -#include "bus-message.h" + +#include "alloc-util.h" +#include "bus-gvariant.h" #include "bus-internal.h" -#include "bus-type.h" +#include "bus-message.h" #include "bus-signature.h" -#include "bus-gvariant.h" +#include "bus-type.h" #include "bus-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "memfd-util.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" +#include "utf8.h" +#include "util.h" static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored); @@ -113,8 +115,7 @@ static void message_reset_containers(sd_bus_message *m) { free(m->containers[i].offsets); } - free(m->containers); - m->containers = NULL; + m->containers = mfree(m->containers); m->n_containers = m->containers_allocated = 0; m->root_container.index = 0; @@ -144,11 +145,7 @@ static void message_free(sd_bus_message *m) { if (m->iovec != m->iovec_fixed) free(m->iovec); - if (m->destination_ptr) { - free(m->destination_ptr); - m->destination_ptr = NULL; - } - + m->destination_ptr = mfree(m->destination_ptr); message_reset_containers(m); free(m->root_container.signature); free(m->root_container.offsets); @@ -184,7 +181,7 @@ static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, b if (!np) goto poison; } else { - /* Initially, the header is allocated as part of of + /* Initially, the header is allocated as part of * the sd_bus_message itself, let's replace it by * dynamic data */ @@ -608,8 +605,8 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) { m->header = (struct bus_header*) ((uint8_t*) m + ALIGN(sizeof(struct sd_bus_message))); m->header->endian = BUS_NATIVE_ENDIAN; m->header->type = type; - m->header->version = bus ? bus->message_version : 1; - m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); + m->header->version = bus->message_version; + m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING); m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m); m->bus = sd_bus_ref(bus); @@ -803,7 +800,7 @@ _public_ int sd_bus_message_new_method_errorf( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; assert_return(name, -EINVAL); @@ -822,7 +819,7 @@ _public_ int sd_bus_message_new_method_errno( int error, const sd_bus_error *p) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; if (sd_bus_error_is_set(p)) return sd_bus_message_new_method_error(call, m, p); @@ -839,7 +836,7 @@ _public_ int sd_bus_message_new_method_errnof( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; va_list ap; va_start(ap, format); @@ -920,7 +917,9 @@ fail: } _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { - assert_return(m, NULL); + + if (!m) + return NULL; assert(m->n_ref > 0); m->n_ref++; @@ -1028,7 +1027,9 @@ _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) { _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) { assert_return(m, NULL); - assert_return(sd_bus_error_is_set(&m->error), NULL); + + if (!sd_bus_error_is_set(&m->error)) + return NULL; return &m->error; } @@ -1130,10 +1131,7 @@ _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) { assert_return(!m->sealed, -EPERM); assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED; - else - m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b); return 0; } @@ -1142,10 +1140,7 @@ _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) { assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START; - else - m->header->flags |= BUS_MESSAGE_NO_AUTO_START; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b); return 0; } @@ -1154,10 +1149,7 @@ _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message * assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; - else - m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; + SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b); return 0; } @@ -1197,7 +1189,7 @@ struct bus_body_part *message_append_part(sd_bus_message *m) { part->memfd = -1; m->body_end = part; - m->n_body_parts ++; + m->n_body_parts++; return part; } @@ -1642,7 +1634,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void } if (type == SD_BUS_TYPE_UNIX_FD) - m->n_fds ++; + m->n_fds++; if (c->enclosing != SD_BUS_TYPE_ARRAY) c->index++; @@ -2209,7 +2201,14 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, assert(!c->need_offsets || i == c->n_offsets); assert(c->need_offsets || n_variable == 0); - if (n_variable <= 0) { + if (isempty(c->signature)) { + /* The unary type is encoded as fixed 1 byte padding */ + a = message_extend_body(m, 1, 1, add_offset, false); + if (!a) + return -ENOMEM; + + *a = 0; + } else if (n_variable <= 0) { int alignment = 1; /* Structures with fixed-size members only have to be @@ -2379,9 +2378,9 @@ int bus_message_append_ap( t = types; if (n_array != (unsigned) -1) - n_array --; + n_array--; else { - types ++; + types++; n_struct--; } @@ -2623,8 +2622,7 @@ _public_ int sd_bus_message_append_array( if (r < 0) return r; - if (size > 0) - memcpy(p, ptr, size); + memcpy_safe(p, ptr, size); return 0; } @@ -2680,7 +2678,7 @@ _public_ int sd_bus_message_append_array_memfd( int r; assert_return(m, -EINVAL); - assert_return(memfd >= 0, -EINVAL); + assert_return(memfd >= 0, -EBADF); assert_return(bus_type_is_trivial(type), -EINVAL); assert_return(size > 0, -EINVAL); assert_return(!m->sealed, -EPERM); @@ -2756,7 +2754,7 @@ _public_ int sd_bus_message_append_string_memfd( int r; assert_return(m, -EINVAL); - assert_return(memfd >= 0, -EINVAL); + assert_return(memfd >= 0, -EBADF); assert_return(size > 0, -EINVAL); assert_return(!m->sealed, -EPERM); assert_return(!m->poisoned, -ESTALE); @@ -2867,7 +2865,7 @@ static int bus_message_close_header(sd_bus_message *m) { /* The actual user data is finished now, we just complete the variant and struct now (at least on gvariant). Remember - this position, so that during parsing we know where to to + this position, so that during parsing we know where to put the outer container end. */ m->user_body_size = m->body_size; @@ -2899,18 +2897,20 @@ static int bus_message_close_header(sd_bus_message *m) { signature = strempty(m->root_container.signature); l = strlen(signature); - sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l, 1); - d = message_extend_body(m, 1, 1 + l + sz, false, true); + sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l + 2, 1); + d = message_extend_body(m, 1, 1 + l + 2 + sz, false, true); if (!d) return -ENOMEM; *(uint8_t*) d = 0; - memcpy((uint8_t*) d + 1, signature, l); + *((uint8_t*) d + 1) = SD_BUS_TYPE_STRUCT_BEGIN; + memcpy((uint8_t*) d + 2, signature, l); + *((uint8_t*) d + 1 + l + 1) = SD_BUS_TYPE_STRUCT_END; - bus_gvariant_write_word_le((uint8_t*) d + 1 + l, sz, sizeof(struct bus_header) + m->fields_size); + bus_gvariant_write_word_le((uint8_t*) d + 1 + l + 2, sz, sizeof(struct bus_header) + m->fields_size); m->footer = d; - m->footer_accessible = 1 + l + sz; + m->footer_accessible = 1 + l + 2 + sz; } else { m->header->dbus1.fields_size = m->fields_size; m->header->dbus1.body_size = m->body_size; @@ -3814,6 +3814,14 @@ static int build_struct_offsets( assert(n_offsets); if (isempty(signature)) { + /* Unary type is encoded as *fixed* 1 byte padding */ + r = message_peek_body(m, &m->rindex, 1, 1, &q); + if (r < 0) + return r; + + if (*(uint8_t *) q != 0) + return -EBADMSG; + *item_size = 0; *offsets = NULL; *n_offsets = 0; @@ -3849,7 +3857,7 @@ static int build_struct_offsets( if (r < 0) return r; if (r == 0 && p[n] != 0) /* except the last item */ - n_variable ++; + n_variable++; n_total++; p += n; @@ -3954,12 +3962,6 @@ static int enter_struct_or_dict_entry( if (r < 0) return r; - } else if (c->item_size <= 0) { - - /* gvariant empty struct */ - *item_size = 0; - *offsets = NULL; - *n_offsets = 0; } else /* gvariant with contents */ return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets); @@ -4146,7 +4148,14 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, w->before = before; w->begin = m->rindex; - w->end = m->rindex + c->item_size; + + /* Unary type has fixed size of 1, but virtual size of 0 */ + if (BUS_MESSAGE_IS_GVARIANT(m) && + type == SD_BUS_TYPE_STRUCT && + isempty(signature)) + w->end = m->rindex + 0; + else + w->end = m->rindex + c->item_size; w->array_size = array_size; w->item_size = item_size; @@ -4448,9 +4457,9 @@ static int message_read_ap( t = types; if (n_array != (unsigned) -1) - n_array --; + n_array--; else { - types ++; + types++; n_struct--; } @@ -4756,7 +4765,6 @@ _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) { r = sd_bus_message_skip(m, s); if (r < 0) return r; - assert(r != 0); r = sd_bus_message_exit_container(m); if (r < 0) @@ -5164,11 +5172,21 @@ int bus_message_parse_fields(sd_bus_message *m) { return -EBADMSG; if (*p == 0) { + size_t l; char *c; - /* We found the beginning of the signature string, yay! */ + /* We found the beginning of the signature + * string, yay! We require the body to be a + * structure, so verify it and then strip the + * opening/closing brackets. */ - c = strndup(p + 1, ((char*) m->footer + m->footer_accessible) - p - (1 + sz)); + l = ((char*) m->footer + m->footer_accessible) - p - (1 + sz); + if (l < 2 || + p[1] != SD_BUS_TYPE_STRUCT_BEGIN || + p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END) + return -EBADMSG; + + c = strndup(p + 1 + 1, l - 2); if (!c) return -ENOMEM; @@ -5589,21 +5607,23 @@ _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) { return 1; } -int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv) { - const char *contents; +static int bus_message_get_arg_skip( + sd_bus_message *m, + unsigned i, + char *_type, + const char **_contents) { + unsigned j; - char type; int r; - assert(m); - assert(str); - assert(strv); - r = sd_bus_message_rewind(m, true); if (r < 0) return r; for (j = 0;; j++) { + const char *contents; + char type; + r = sd_bus_message_peek_type(m, &type, &contents); if (r < 0) return r; @@ -5615,31 +5635,56 @@ int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ** !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g"))) return -ENXIO; - if (j >= i) - break; + if (j >= i) { + if (_contents) + *_contents = contents; + if (_type) + *_type = type; + return 0; + } r = sd_bus_message_skip(m, NULL); if (r < 0) return r; } - if (type == SD_BUS_TYPE_ARRAY) { +} - r = sd_bus_message_read_strv(m, strv); - if (r < 0) - return r; +int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) { + char type; + int r; + + assert(m); + assert(str); - *str = NULL; + r = bus_message_get_arg_skip(m, i, &type, NULL); + if (r < 0) + return r; - } else { - r = sd_bus_message_read_basic(m, type, str); - if (r < 0) - return r; + if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) + return -ENXIO; - *strv = NULL; - } + return sd_bus_message_read_basic(m, type, str); +} - return 0; +int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) { + const char *contents; + char type; + int r; + + assert(m); + assert(strv); + + r = bus_message_get_arg_skip(m, i, &type, &contents); + if (r < 0) + return r; + + if (type != SD_BUS_TYPE_ARRAY) + return -ENXIO; + if (!STR_IN_SET(contents, "s", "o", "g")) + return -ENXIO; + + return sd_bus_message_read_strv(m, strv); } _public_ int sd_bus_message_get_errno(sd_bus_message *m) { @@ -5783,7 +5828,7 @@ _public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) { } int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) { - _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL; usec_t timeout; int r; diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h index 088d5b1109..4710c106b9 100644 --- a/src/libsystemd/sd-bus/bus-message.h +++ b/src/libsystemd/sd-bus/bus-message.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,15 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <byteswap.h> +#include <stdbool.h> #include <sys/socket.h> -#include "macro.h" #include "sd-bus.h" -#include "time-util.h" + #include "bus-creds.h" #include "bus-protocol.h" +#include "macro.h" +#include "time-util.h" struct bus_container { char enclosing; @@ -218,7 +217,8 @@ int bus_message_from_malloc( const char *label, sd_bus_message **ret); -int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv); +int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str); +int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv); int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap); diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index cbdf6552f9..9bd07ffcab 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,16 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" -#include "set.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-introspect.h" #include "bus-message.h" -#include "bus-type.h" +#include "bus-objects.h" #include "bus-signature.h" -#include "bus-introspect.h" -#include "bus-util.h" #include "bus-slot.h" -#include "bus-objects.h" +#include "bus-type.h" +#include "bus-util.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" static int node_vtable_get_userdata( sd_bus *bus, @@ -68,6 +68,12 @@ static int node_vtable_get_userdata( return 1; } +static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) { + assert(p); + + return (uint8_t*) u + p->x.method.offset; +} + static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) { assert(p); @@ -139,7 +145,7 @@ static int add_enumerated_to_set( continue; } - if (!object_path_is_valid(*k)){ + if (!object_path_is_valid(*k)) { free(*k); r = -EINVAL; continue; @@ -163,10 +169,18 @@ static int add_enumerated_to_set( return 0; } +enum { + /* if set, add_subtree() works recursively */ + CHILDREN_RECURSIVE = (1U << 1), + /* if set, add_subtree() scans object-manager hierarchies recursively */ + CHILDREN_SUBHIERARCHIES = (1U << 0), +}; + static int add_subtree_to_set( sd_bus *bus, const char *prefix, struct node *n, + unsigned int flags, Set *s, sd_bus_error *error) { @@ -198,11 +212,14 @@ static int add_subtree_to_set( if (r < 0 && r != -EEXIST) return r; - r = add_subtree_to_set(bus, prefix, i, s, error); - if (r < 0) - return r; - if (bus->nodes_modified) - return 0; + if ((flags & CHILDREN_RECURSIVE) && + ((flags & CHILDREN_SUBHIERARCHIES) || !i->object_managers)) { + r = add_subtree_to_set(bus, prefix, i, flags, s, error); + if (r < 0) + return r; + if (bus->nodes_modified) + return 0; + } } return 0; @@ -212,6 +229,7 @@ static int get_child_nodes( sd_bus *bus, const char *prefix, struct node *n, + unsigned int flags, Set **_s, sd_bus_error *error) { @@ -227,7 +245,7 @@ static int get_child_nodes( if (!s) return -ENOMEM; - r = add_subtree_to_set(bus, prefix, n, s, error); + r = add_subtree_to_set(bus, prefix, n, flags, s, error); if (r < 0) { set_free_free(s); return r; @@ -252,7 +270,7 @@ static int node_callbacks_run( assert(found_object); LIST_FOREACH(callbacks, c, first) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; sd_bus_slot *slot; if (bus->nodes_modified) @@ -319,7 +337,7 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, if (cap == 0) cap = CAP_SYS_ADMIN; else - cap --; + cap--; r = sd_bus_query_sender_privilege(m, cap); if (r < 0) @@ -337,7 +355,7 @@ static int method_callbacks_run( bool require_fallback, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *signature; void *u; int r; @@ -360,6 +378,8 @@ static int method_callbacks_run( if (bus->nodes_modified) return 0; + u = vtable_method_convert_userdata(c->vtable, u); + *found_object = true; if (c->last_iteration == bus->iteration_counter) @@ -558,8 +578,8 @@ static int property_get_set_callbacks_run( bool is_get, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus_slot *slot; void *u = NULL; int r; @@ -738,6 +758,9 @@ static int vtable_append_all_properties( if (v->flags & SD_BUS_VTABLE_HIDDEN) continue; + if (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT) + continue; + r = vtable_append_one_property(bus, reply, path, c, v, userdata, error); if (r < 0) return r; @@ -756,7 +779,7 @@ static int property_get_all_callbacks_run( const char *iface, bool *found_object) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; struct node_vtable *c; bool found_interface; int r; @@ -779,7 +802,7 @@ static int property_get_all_callbacks_run( streq(iface, "org.freedesktop.DBus.Introspectable"); LIST_FOREACH(vtables, c, first) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; void *u; if (require_fallback && !c->is_fallback) @@ -856,7 +879,7 @@ static int bus_node_exists( } LIST_FOREACH(vtables, c, n->vtables) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (require_fallback && !c->is_fallback) continue; @@ -878,8 +901,8 @@ static int process_introspect( bool require_fallback, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_set_free_free_ Set *s = NULL; const char *previous_interface = NULL; struct introspect intro; @@ -892,7 +915,7 @@ static int process_introspect( assert(n); assert(found_object); - r = get_child_nodes(bus, m->path, n, &s, &error); + r = get_child_nodes(bus, m->path, n, 0, &s, &error); if (r < 0) return bus_maybe_reply_error(m, r, &error); if (bus->nodes_modified) @@ -1139,8 +1162,8 @@ static int process_get_managed_objects( bool require_fallback, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_set_free_free_ Set *s = NULL; Iterator i; char *path; @@ -1158,16 +1181,12 @@ static int process_get_managed_objects( if (require_fallback || !n->object_managers) return 0; - r = get_child_nodes(bus, m->path, n, &s, &error); + r = get_child_nodes(bus, m->path, n, CHILDREN_RECURSIVE, &s, &error); if (r < 0) return r; if (bus->nodes_modified) return 0; - r = set_put_strdup(s, m->path); - if (r < 0) - return r; - r = sd_bus_message_new_method_return(m, &reply); if (r < 0) return r; @@ -1467,6 +1486,32 @@ void bus_node_gc(sd_bus *b, struct node *n) { free(n); } +static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) { + struct node *n; + + assert(bus); + assert(path); + + n = hashmap_get(bus->nodes, path); + if (!n) { + char *prefix; + + prefix = alloca(strlen(path) + 1); + OBJECT_PATH_FOREACH_PREFIX(prefix, path) { + n = hashmap_get(bus->nodes, prefix); + if (n) + break; + } + } + + while (n && !n->object_managers) + n = n->parent; + + if (out) + *out = n; + return !!n; +} + static int bus_add_object( sd_bus *bus, sd_bus_slot **slot, @@ -1533,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) { @@ -1707,8 +1741,9 @@ static int add_object_vtable_internal( if (!member_name_is_valid(v->x.property.member) || !signature_is_single(v->x.property.signature, false) || !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) || - v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY || + (v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) || (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 || + ((v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) && (v->flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)) || (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) { r = -EINVAL; goto fail; @@ -1844,8 +1879,8 @@ static int emit_properties_changed_on_interface( bool *found_interface, char **names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; bool has_invalidating = false, has_changing = false; struct vtable_member key = {}; struct node_vtable *c; @@ -2139,7 +2174,7 @@ static int object_added_append_all_prefix( return 0; LIST_FOREACH(vtables, c, n->vtables) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; void *u = NULL; if (require_fallback && !c->is_fallback) @@ -2268,7 +2303,8 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { BUS_DONT_DESTROY(bus); - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct node *object_manager; int r; /* @@ -2289,11 +2325,17 @@ _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + do { bus->nodes_modified = false; m = sd_bus_message_unref(m); - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); if (r < 0) return r; @@ -2345,7 +2387,7 @@ static int object_removed_append_all_prefix( return 0; LIST_FOREACH(vtables, c, n->vtables) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; void *u = NULL; if (require_fallback && !c->is_fallback) @@ -2431,7 +2473,8 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { BUS_DONT_DESTROY(bus); - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct node *object_manager; int r; /* @@ -2452,11 +2495,17 @@ _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { if (!BUS_IS_OPEN(bus->state)) return -ENOTCONN; + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + do { bus->nodes_modified = false; m = sd_bus_message_unref(m); - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); if (r < 0) return r; @@ -2492,7 +2541,7 @@ static int interfaces_added_append_one_prefix( const char *interface, bool require_fallback) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool found_interface = false; struct node_vtable *c; struct node *n; @@ -2587,7 +2636,8 @@ static int interfaces_added_append_one( _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) { BUS_DONT_DESTROY(bus); - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct node *object_manager; char **i; int r; @@ -2601,11 +2651,17 @@ _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, ch if (strv_isempty(interfaces)) return 0; + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + do { bus->nodes_modified = false; m = sd_bus_message_unref(m); - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"); if (r < 0) return r; @@ -2664,7 +2720,8 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c } _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct node *object_manager; int r; assert_return(bus, -EINVAL); @@ -2677,7 +2734,13 @@ _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, if (strv_isempty(interfaces)) return 0; - r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); + r = bus_find_parent_object_manager(bus, &object_manager, path); + if (r < 0) + return r; + if (r == 0) + return -ESRCH; + + r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"); if (r < 0) return r; diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h index 4373fae89c..e0b8c534ed 100644 --- a/src/libsystemd/sd-bus/bus-objects.h +++ b/src/libsystemd/sd-bus/bus-objects.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-protocol.h b/src/libsystemd/sd-bus/bus-protocol.h index 183af89a63..9d180cb284 100644 --- a/src/libsystemd/sd-bus/bus-protocol.h +++ b/src/libsystemd/sd-bus/bus-protocol.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-signature.c b/src/libsystemd/sd-bus/bus-signature.c index 1e5bf4821d..7bc243494a 100644 --- a/src/libsystemd/sd-bus/bus-signature.c +++ b/src/libsystemd/sd-bus/bus-signature.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-signature.h b/src/libsystemd/sd-bus/bus-signature.h index c4fed0b53d..1e0cd7f587 100644 --- a/src/libsystemd/sd-bus/bus-signature.h +++ b/src/libsystemd/sd-bus/bus-signature.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index b149ea16da..8e9074c7df 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,9 +18,12 @@ ***/ #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-control.h" #include "bus-objects.h" #include "bus-slot.h" +#include "string-util.h" sd_bus_slot *bus_slot_allocate( sd_bus *bus, @@ -54,7 +55,9 @@ sd_bus_slot *bus_slot_allocate( } _public_ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot) { - assert_return(slot, NULL); + + if (!slot) + return NULL; assert(slot->n_ref > 0); @@ -203,7 +206,7 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) { assert(slot->n_ref > 0); if (slot->n_ref > 1) { - slot->n_ref --; + slot->n_ref--; return NULL; } diff --git a/src/libsystemd/sd-bus/bus-slot.h b/src/libsystemd/sd-bus/bus-slot.h index 23a15e4d02..3b8b94dc6b 100644 --- a/src/libsystemd/sd-bus/bus-slot.h +++ b/src/libsystemd/sd-bus/bus-slot.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "bus-internal.h" sd_bus_slot *bus_slot_allocate(sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata); diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 735a775cb4..cfd7753139 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,22 +18,29 @@ ***/ #include <endian.h> +#include <poll.h> #include <stdlib.h> #include <unistd.h> -#include <poll.h> +#include "sd-bus.h" #include "sd-daemon.h" -#include "util.h" -#include "macro.h" -#include "missing.h" -#include "utf8.h" -#include "formats-util.h" -#include "signal-util.h" -#include "sd-bus.h" -#include "bus-socket.h" +#include "alloc-util.h" #include "bus-internal.h" #include "bus-message.h" +#include "bus-socket.h" +#include "fd-util.h" +#include "formats-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "missing.h" +#include "selinux-util.h" +#include "signal-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "user-util.h" +#include "utf8.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -55,7 +60,7 @@ static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) { i->iov_base = NULL; i->iov_len = 0; - (*idx) ++; + (*idx)++; } } @@ -216,7 +221,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) { peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y); } - if (!sd_id128_equal(b->server_id, SD_ID128_NULL) && + if (!sd_id128_is_null(b->server_id) && !sd_id128_equal(b->server_id, peer)) return -EPERM; @@ -345,7 +350,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) { if (!p) return -ENOMEM; - memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); + memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len); memcpy(p + b->auth_iovec[0].iov_len, t, l); b->auth_iovec[0].iov_base = p; @@ -602,9 +607,11 @@ static void bus_get_peercred(sd_bus *b) { b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; /* Get the SELinux context of the peer */ - r = getpeersec(b->input_fd, &b->label); - if (r < 0 && r != -EOPNOTSUPP) - log_debug_errno(r, "Failed to determine peer security context: %m"); + if (mac_selinux_have()) { + r = getpeersec(b->input_fd, &b->label); + if (r < 0 && r != -EOPNOTSUPP) + log_debug_errno(r, "Failed to determine peer security context: %m"); + } } static int bus_socket_start_auth_client(sd_bus *b) { @@ -780,7 +787,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { n = m->n_iovec * sizeof(struct iovec); iov = alloca(n); - memcpy(iov, m->iovec, n); + memcpy_safe(iov, m->iovec, n); j = 0; iovec_advance(iov, &j, *idx); @@ -985,13 +992,13 @@ 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; } - memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); bus->fds = f; bus->n_fds += n; } else diff --git a/src/libsystemd/sd-bus/bus-socket.h b/src/libsystemd/sd-bus/bus-socket.h index 5a1c7d4cf2..684feead74 100644 --- a/src/libsystemd/sd-bus/bus-socket.h +++ b/src/libsystemd/sd-bus/bus-socket.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index e43891be25..00e93a215f 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,20 +18,33 @@ ***/ #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-track.h" +#include "bus-util.h" + +struct track_item { + unsigned n_ref; + char *name; + sd_bus_slot *slot; +}; struct sd_bus_track { unsigned n_ref; + unsigned n_adding; /* are we in the process of adding a new name? */ sd_bus *bus; sd_bus_track_handler_t handler; void *userdata; Hashmap *names; LIST_FIELDS(sd_bus_track, queue); Iterator iterator; - bool in_queue; - bool modified; + bool in_list:1; /* In bus->tracks? */ + bool in_queue:1; /* In bus->track_queue? */ + bool modified:1; + bool recursive:1; + + LIST_FIELDS(sd_bus_track, tracks); }; #define MATCH_PREFIX \ @@ -56,15 +67,47 @@ struct sd_bus_track { _x; \ }) +static struct track_item* track_item_free(struct track_item *i) { + + if (!i) + return NULL; + + sd_bus_slot_unref(i->slot); + free(i->name); + free(i); + + return NULL; +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free); + static void bus_track_add_to_queue(sd_bus_track *track) { assert(track); + /* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of + * conditions. */ + + /* Already in the queue? */ if (track->in_queue) return; + /* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait + * until the addition is complete. */ + if (track->n_adding > 0) + return; + + /* still referenced? */ + if (hashmap_size(track->names) > 0) + return; + + /* Nothing to call? */ if (!track->handler) return; + /* Already closed? */ + if (!track->in_list) + return; + LIST_PREPEND(queue, track->bus->track_queue, track); track->in_queue = true; } @@ -79,6 +122,24 @@ static void bus_track_remove_from_queue(sd_bus_track *track) { track->in_queue = false; } +static int bus_track_remove_name_fully(sd_bus_track *track, const char *name) { + struct track_item *i; + + assert(track); + assert(name); + + i = hashmap_remove(track->names, name); + if (!i) + return 0; + + track_item_free(i); + + bus_track_add_to_queue(track); + + track->modified = true; + return 1; +} + _public_ int sd_bus_track_new( sd_bus *bus, sd_bus_track **track, @@ -102,6 +163,9 @@ _public_ int sd_bus_track_new( t->userdata = userdata; t->bus = sd_bus_ref(bus); + LIST_PREPEND(tracks, bus->tracks, t); + t->in_list = true; + bus_track_add_to_queue(t); *track = t; @@ -109,7 +173,9 @@ _public_ int sd_bus_track_new( } _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) { - assert_return(track, NULL); + + if (!track) + return NULL; assert(track->n_ref > 0); @@ -119,7 +185,7 @@ _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) { } _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) { - const char *n; + struct track_item *i; if (!track) return NULL; @@ -127,12 +193,15 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) { assert(track->n_ref > 0); if (track->n_ref > 1) { - track->n_ref --; + track->n_ref--; return NULL; } - while ((n = hashmap_first_key(track->names))) - sd_bus_track_remove_name(track, n); + while ((i = hashmap_steal_first(track->names))) + track_item_free(i); + + if (track->in_list) + LIST_REMOVE(tracks, track->bus->tracks, track); bus_track_remove_from_queue(track); hashmap_free(track->names); @@ -154,49 +223,76 @@ static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus if (r < 0) return 0; - sd_bus_track_remove_name(track, name); + bus_track_remove_name_fully(track, name); return 0; } _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; - _cleanup_free_ char *n = NULL; + _cleanup_(track_item_freep) struct track_item *n = NULL; + struct track_item *i; const char *match; int r; assert_return(track, -EINVAL); assert_return(service_name_is_valid(name), -EINVAL); + i = hashmap_get(track->names, name); + if (i) { + if (track->recursive) { + unsigned k = track->n_ref + 1; + + if (k < track->n_ref) /* Check for overflow */ + return -EOVERFLOW; + + track->n_ref = k; + } + + bus_track_remove_from_queue(track); + return 0; + } + r = hashmap_ensure_allocated(&track->names, &string_hash_ops); if (r < 0) return r; - n = strdup(name); + n = new0(struct track_item, 1); if (!n) return -ENOMEM; + n->name = strdup(name); + if (!n->name) + return -ENOMEM; /* First, subscribe to this name */ - match = MATCH_FOR_NAME(n); - r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track); - if (r < 0) + match = MATCH_FOR_NAME(name); + + bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */ + + track->n_adding++; /* make sure we aren't dispatched while we synchronously add this match */ + r = sd_bus_add_match(track->bus, &n->slot, match, on_name_owner_changed, track); + track->n_adding--; + if (r < 0) { + bus_track_add_to_queue(track); return r; + } - r = hashmap_put(track->names, n, slot); - if (r == -EEXIST) - return 0; - if (r < 0) + r = hashmap_put(track->names, n->name, n); + if (r < 0) { + bus_track_add_to_queue(track); return r; + } - /* Second, check if it is currently existing, or maybe - * doesn't, or maybe disappeared already. */ - r = sd_bus_get_name_creds(track->bus, n, 0, NULL); + /* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */ + track->n_adding++; /* again, make sure this isn't dispatch while we are working in it */ + r = sd_bus_get_name_creds(track->bus, name, 0, NULL); + track->n_adding--; if (r < 0) { - hashmap_remove(track->names, n); + hashmap_remove(track->names, name); + bus_track_add_to_queue(track); return r; } + n->n_ref = 1; n = NULL; - slot = NULL; bus_track_remove_from_queue(track); track->modified = true; @@ -205,37 +301,48 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { } _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) { - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; - _cleanup_free_ char *n = NULL; + struct track_item *i; assert_return(name, -EINVAL); - if (!track) + if (!track) /* Treat a NULL track object as an empty track object */ return 0; - slot = hashmap_remove2(track->names, (char*) name, (void**) &n); - if (!slot) - return 0; + if (!track->recursive) + return bus_track_remove_name_fully(track, name); - if (hashmap_isempty(track->names)) - bus_track_add_to_queue(track); + i = hashmap_get(track->names, name); + if (!i) + return -EUNATCH; + if (i->n_ref <= 0) + return -EUNATCH; - track->modified = true; + i->n_ref--; + + if (i->n_ref <= 0) + return bus_track_remove_name_fully(track, name); return 1; } _public_ unsigned sd_bus_track_count(sd_bus_track *track) { - if (!track) + + if (!track) /* Let's consider a NULL object equivalent to an empty object */ return 0; + /* This signature really should have returned an int, so that we can propagate errors. But well, ... Also, note + * that this returns the number of names being watched, and multiple references to the same name are not + * counted. */ + return hashmap_size(track->names); } _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name) { - assert_return(track, NULL); assert_return(name, NULL); + if (!track) /* Let's consider a NULL object equivalent to an empty object */ + return NULL; + return hashmap_get(track->names, (void*) name) ? name : NULL; } @@ -271,6 +378,9 @@ _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) { assert_return(track, -EINVAL); assert_return(m, -EINVAL); + if (sd_bus_message_get_bus(m) != track->bus) + return -EINVAL; + sender = sd_bus_message_get_sender(m); if (!sender) return -EINVAL; @@ -281,9 +391,14 @@ _public_ int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) { _public_ int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) { const char *sender; - assert_return(track, -EINVAL); assert_return(m, -EINVAL); + if (!track) /* Treat a NULL track object as an empty track object */ + return 0; + + if (sd_bus_message_get_bus(m) != track->bus) + return -EINVAL; + sender = sd_bus_message_get_sender(m); if (!sender) return -EINVAL; @@ -301,7 +416,6 @@ void bus_track_dispatch(sd_bus_track *track) { int r; assert(track); - assert(track->in_queue); assert(track->handler); bus_track_remove_from_queue(track); @@ -317,6 +431,34 @@ void bus_track_dispatch(sd_bus_track *track) { sd_bus_track_unref(track); } +void bus_track_close(sd_bus_track *track) { + struct track_item *i; + + assert(track); + + /* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it + * immediately, as we are closing now, but first flush out all names. */ + + if (!track->in_list) + return; /* We already closed this one, don't close it again. */ + + /* Remember that this one is closed now */ + LIST_REMOVE(tracks, track->bus->tracks, track); + track->in_list = false; + + /* If there's no name in this one anyway, we don't have to dispatch */ + if (hashmap_isempty(track->names)) + return; + + /* Let's flush out all names */ + while ((i = hashmap_steal_first(track->names))) + track_item_free(i); + + /* Invoke handler */ + if (track->handler) + bus_track_dispatch(track); +} + _public_ void *sd_bus_track_get_userdata(sd_bus_track *track) { assert_return(track, NULL); @@ -333,3 +475,55 @@ _public_ void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) { return ret; } + +_public_ int sd_bus_track_set_recursive(sd_bus_track *track, int b) { + assert_return(track, -EINVAL); + + if (track->recursive == !!b) + return 0; + + if (!hashmap_isempty(track->names)) + return -EBUSY; + + track->recursive = b; + return 0; +} + +_public_ int sd_bus_track_get_recursive(sd_bus_track *track) { + assert_return(track, -EINVAL); + + return track->recursive; +} + +_public_ int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m) { + const char *sender; + + assert_return(m, -EINVAL); + + if (!track) /* Let's consider a NULL object equivalent to an empty object */ + return 0; + + if (sd_bus_message_get_bus(m) != track->bus) + return -EINVAL; + + sender = sd_bus_message_get_sender(m); + if (!sender) + return -EINVAL; + + return sd_bus_track_count_name(track, sender); +} + +_public_ int sd_bus_track_count_name(sd_bus_track *track, const char *name) { + struct track_item *i; + + assert_return(service_name_is_valid(name), -EINVAL); + + if (!track) /* Let's consider a NULL object equivalent to an empty object */ + return 0; + + i = hashmap_get(track->names, name); + if (!i) + return 0; + + return i->n_ref; +} diff --git a/src/libsystemd/sd-bus/bus-track.h b/src/libsystemd/sd-bus/bus-track.h index f8690a5239..26bd05f5c7 100644 --- a/src/libsystemd/sd-bus/bus-track.h +++ b/src/libsystemd/sd-bus/bus-track.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,3 +20,4 @@ ***/ void bus_track_dispatch(sd_bus_track *track); +void bus_track_close(sd_bus_track *track); diff --git a/src/libsystemd/sd-bus/bus-type.c b/src/libsystemd/sd-bus/bus-type.c index 6bc7b880a6..c692afc580 100644 --- a/src/libsystemd/sd-bus/bus-type.c +++ b/src/libsystemd/sd-bus/bus-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h index 581574ab73..5c87eb5f08 100644 --- a/src/libsystemd/sd-bus/bus-type.h +++ b/src/libsystemd/sd-bus/bus-type.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,10 @@ #include <stdbool.h> -#include "macro.h" #include "sd-bus.h" +#include "macro.h" + bool bus_type_is_valid(char c) _const_; bool bus_type_is_valid_in_signature(char c) _const_; bool bus_type_is_basic(char c) _const_; diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c index 15c10da7e9..b09509f8e1 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.c +++ b/src/libsystemd/sd-bus/busctl-introspect.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "xml.h" -#include "sd-bus-vtable.h" +#include "sd-bus.h" +#include "alloc-util.h" #include "busctl-introspect.h" +#include "string-util.h" +#include "util.h" +#include "xml.h" #define NODE_DEPTH_MAX 16 @@ -55,8 +55,7 @@ static void context_reset_member(Context *c) { } static void context_reset_interface(Context *c) { - free(c->interface_name); - c->interface_name = NULL; + c->interface_name = mfree(c->interface_name); c->interface_flags = 0; context_reset_member(c); @@ -462,9 +461,8 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth } } - free(argument_type); - free(argument_direction); - argument_type = argument_direction = NULL; + argument_type = mfree(argument_type); + argument_direction = mfree(argument_direction); } state = STATE_METHOD; @@ -604,8 +602,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth if (!strextend(&context->member_signature, argument_type, NULL)) return log_oom(); - free(argument_type); - argument_type = NULL; + argument_type = mfree(argument_type); } state = STATE_SIGNAL; diff --git a/src/libsystemd/sd-bus/busctl-introspect.h b/src/libsystemd/sd-bus/busctl-introspect.h index ea807d5973..d922e352db 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.h +++ b/src/libsystemd/sd-bus/busctl-introspect.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 6aaaf0e5ec..2c3f591053 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,22 +19,27 @@ #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 "alloc-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 "escape.h" +#include "fd-util.h" +#include "locale-util.h" +#include "log.h" +#include "pager.h" +#include "parse-util.h" +#include "path-util.h" +#include "set.h" +#include "strv.h" #include "terminal-util.h" +#include "user-util.h" +#include "util.h" static bool arg_no_pager = false; static bool arg_legend = true; @@ -59,15 +62,6 @@ static bool arg_allow_interactive_authorization = true; static bool arg_augment_creds = true; static usec_t arg_timeout = 0; -static void pager_open_if_enabled(void) { - - /* Cache result before we open the pager */ - if (arg_no_pager) - return; - - pager_open(false); -} - #define NAME_IS_ACQUIRED INT_TO_PTR(1) #define NAME_IS_ACTIVATABLE INT_TO_PTR(2) @@ -92,7 +86,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { if (r < 0) return log_error_errno(r, "Failed to list names: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); names = hashmap_new(&string_hash_ops); if (!names) @@ -132,7 +126,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { } STRV_FOREACH(i, merged) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_id128_t mid; if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) { @@ -255,8 +249,8 @@ static void print_subtree(const char *prefix, const char *path, char **l) { l++; } - vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL)); - space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE)); + vertical = strjoina(prefix, special_glyph(TREE_VERTICAL)); + space = strjoina(prefix, special_glyph(TREE_SPACE)); for (;;) { bool has_more = false; @@ -277,7 +271,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) { n++; } - printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l); + printf("%s%s%s\n", prefix, special_glyph(has_more ? TREE_BRANCH : TREE_RIGHT), *l); print_subtree(has_more ? vertical : space, *l, l); l = n; @@ -286,7 +280,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) { static void print_tree(const char *prefix, char **l) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); prefix = strempty(prefix); @@ -329,8 +323,8 @@ static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *p .on_path = on_path, }; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *xml; int r; @@ -406,7 +400,7 @@ static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool m p = NULL; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); l = set_get_strv(done); if (!l) @@ -435,7 +429,7 @@ static int tree(sd_bus *bus, char **argv) { if (r < 0) return log_error_errno(r, "Failed to get name list: %m"); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); STRV_FOREACH(i, names) { int q; @@ -449,7 +443,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) @@ -465,8 +459,8 @@ static int tree(sd_bus *bus, char **argv) { printf("\n"); if (argv[2]) { - pager_open_if_enabled(); - printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off()); + pager_open(arg_no_pager, false); + printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); } q = tree_one(bus, *i, NULL, !!argv[2]); @@ -498,8 +492,10 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) { } basic; r = sd_bus_message_peek_type(m, &type, &contents); - if (r <= 0) + if (r < 0) return r; + if (r == 0) + return needs_space; if (bus_type_is_container(type) > 0) { @@ -530,18 +526,23 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) { fputc(' ', f); fprintf(f, "%u", n); + needs_space = true; + } else if (type == SD_BUS_TYPE_VARIANT) { if (needs_space) fputc(' ', f); fprintf(f, "%s", contents); + needs_space = true; } - r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT)); + r = format_cmdline(m, f, needs_space); if (r < 0) return r; + needs_space = r > 0; + r = sd_bus_message_exit_container(m); if (r < 0) return r; @@ -629,22 +630,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) { @@ -656,28 +659,15 @@ static int member_compare_func(const void *a, const void *b) { assert(x->type); assert(y->type); - if (!x->interface && y->interface) - return -1; - if (x->interface && !y->interface) - return 1; - if (x->interface && y->interface) { - d = strcmp(x->interface, y->interface); - if (d != 0) - return d; - } + d = strcmp_ptr(x->interface, y->interface); + if (d != 0) + return d; d = strcmp(x->type, y->type); if (d != 0) return d; - if (!x->name && y->name) - return -1; - if (x->name && !y->name) - return 1; - if (x->name && y->name) - return strcmp(x->name, y->name); - - return 0; + return strcmp_ptr(x->name, y->name); } static int member_compare_funcp(const void *a, const void *b) { @@ -873,8 +863,8 @@ static int introspect(sd_bus *bus, char **argv) { .on_property = on_property, }; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(member_set_freep) Set *members = NULL; Iterator i; Member *m; @@ -993,7 +983,7 @@ static int introspect(sd_bus *bus, char **argv) { return bus_log_parse_error(r); } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); name_width = strlen("NAME"); type_width = strlen("TYPE"); @@ -1065,7 +1055,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, @@ -1089,10 +1079,21 @@ static int message_pcap(sd_bus_message *m, FILE *f) { } static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) { - bool added_something = false; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char **i; + uint32_t flags = 0; int r; + /* upgrade connection; it's not used for anything else after this call */ + r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(message, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + STRV_FOREACH(i, argv+1) { _cleanup_free_ char *m = NULL; @@ -1105,31 +1106,44 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL if (!m) return log_oom(); - r = sd_bus_add_match(bus, NULL, m, NULL, NULL); + r = sd_bus_message_append_basic(message, 's', m); if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); + return bus_log_create_error(r); - added_something = true; + free(m); + m = strjoin("destination='", *i, "'", NULL); + if (!m) + return log_oom(); + + r = sd_bus_message_append_basic(message, 's', m); + if (r < 0) + return bus_log_create_error(r); } STRV_FOREACH(i, arg_matches) { - r = sd_bus_add_match(bus, NULL, *i, NULL, NULL); + r = sd_bus_message_append_basic(message, 's', *i); if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); - - added_something = true; + return bus_log_create_error(r); } - if (!added_something) { - r = sd_bus_add_match(bus, NULL, "", NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to add match: %m"); + r = sd_bus_message_close_container(message); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(message, 'u', &flags); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, message, arg_timeout, &error, NULL); + if (r < 0) { + log_error("%s", bus_error_message(&error, r)); + return r; } log_info("Monitoring bus message stream."); for (;;) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_process(bus, &m); if (r < 0) @@ -1179,7 +1193,7 @@ static int capture(sd_bus *bus, char *argv[]) { } static int status(sd_bus *bus, char *argv[]) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; pid_t pid; int r; @@ -1209,15 +1223,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, @@ -1486,8 +1500,8 @@ static int message_append_cmdline(sd_bus_message *m, const char *signature, char } static int call(sd_bus *bus, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; int r; assert(bus); @@ -1551,7 +1565,7 @@ static int call(sd_bus *bus, char *argv[]) { if (r == 0 && !arg_quiet) { if (arg_verbose) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = bus_message_dump(reply, stdout, 0); if (r < 0) @@ -1573,7 +1587,7 @@ static int call(sd_bus *bus, char *argv[]) { } static int get_property(sd_bus *bus, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; unsigned n; char **i; int r; @@ -1587,7 +1601,7 @@ static int get_property(sd_bus *bus, char *argv[]) { } STRV_FOREACH(i, argv + 4) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *contents = NULL; char type; @@ -1606,7 +1620,7 @@ static int get_property(sd_bus *bus, char *argv[]) { return bus_log_parse_error(r); if (arg_verbose) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY); if (r < 0) @@ -1631,8 +1645,8 @@ static int get_property(sd_bus *bus, char *argv[]) { } static int set_property(sd_bus *bus, char *argv[]) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; unsigned n; char **p; int r; @@ -1697,6 +1711,7 @@ static int help(void) { " --acquired Only show acquired names\n" " --activatable Only show activatable names\n" " --match=MATCH Only show matching messages\n" + " --size=SIZE Maximum length of captured packet\n" " --list Don't show tree, but simple object path list\n" " --quiet Don't show method call reply\n" " --verbose Show result values in long format\n" @@ -1789,9 +1804,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; @@ -1835,20 +1848,20 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SIZE: { - off_t o; + uint64_t sz; - r = parse_size(optarg, 0, &o); + r = parse_size(optarg, 1024, &sz); if (r < 0) { log_error("Failed to parse size: %s", optarg); return r; } - if ((off_t) (size_t) o != o) { + if ((uint64_t) (size_t) sz != sz) { log_error("Size out of range."); return -E2BIG; } - arg_snaplen = (size_t) o; + arg_snaplen = (size_t) sz; break; } @@ -1974,7 +1987,7 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + sd_bus *bus = NULL; int r; log_parse_environment(); @@ -1990,8 +2003,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (streq_ptr(argv[optind], "monitor") || - streq_ptr(argv[optind], "capture")) { + if (STRPTR_IN_SET(argv[optind], "monitor", "capture")) { r = sd_bus_set_monitor(bus, true); if (r < 0) { @@ -2018,15 +2030,15 @@ int main(int argc, char *argv[]) { } } + r = sd_bus_set_bus_client(bus, true); + if (r < 0) { + log_error_errno(r, "Failed to set bus client: %m"); + goto finish; + } + if (arg_address) r = sd_bus_set_address(bus, arg_address); else { - r = sd_bus_set_bus_client(bus, true); - if (r < 0) { - log_error_errno(r, "Failed to set bus client: %m"); - goto finish; - } - switch (arg_transport) { case BUS_TRANSPORT_LOCAL: @@ -2065,6 +2077,7 @@ int main(int argc, char *argv[]) { r = busctl_main(bus, argc, argv); finish: + sd_bus_flush_close_unref(bus); pager_close(); strv_free(arg_matches); diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 0ca225c617..d746348544 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,34 +18,40 @@ ***/ #include <endian.h> -#include <stdlib.h> -#include <unistd.h> #include <netdb.h> #include <poll.h> -#include <sys/mman.h> #include <pthread.h> - -#include "util.h" -#include "macro.h" -#include "strv.h" -#include "missing.h" -#include "def.h" -#include "cgroup-util.h" -#include "bus-label.h" +#include <stdlib.h> +#include <sys/mman.h> +#include <unistd.h> #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-container.h" +#include "bus-control.h" #include "bus-internal.h" -#include "bus-message.h" -#include "bus-type.h" -#include "bus-socket.h" #include "bus-kernel.h" -#include "bus-control.h" +#include "bus-label.h" +#include "bus-message.h" #include "bus-objects.h" -#include "bus-util.h" -#include "bus-container.h" #include "bus-protocol.h" -#include "bus-track.h" #include "bus-slot.h" +#include "bus-socket.h" +#include "bus-track.h" +#include "bus-type.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "def.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "hostname-util.h" +#include "macro.h" +#include "missing.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define log_debug_bus_message(m) \ do { \ @@ -68,18 +72,18 @@ 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); detach_io_events(b); - if (b->input_fd >= 0) - safe_close(b->input_fd); - - if (b->output_fd >= 0 && b->output_fd != b->input_fd) + if (b->input_fd != b->output_fd) safe_close(b->output_fd); - - b->input_fd = b->output_fd = -1; + b->output_fd = b->input_fd = safe_close(b->input_fd); } static void bus_reset_queues(sd_bus *b) { @@ -88,15 +92,13 @@ static void bus_reset_queues(sd_bus *b) { while (b->rqueue_size > 0) sd_bus_message_unref(b->rqueue[--b->rqueue_size]); - free(b->rqueue); - b->rqueue = NULL; + b->rqueue = mfree(b->rqueue); b->rqueue_allocated = 0; while (b->wqueue_size > 0) sd_bus_message_unref(b->wqueue[--b->wqueue_size]); - free(b->wqueue); - b->wqueue = NULL; + b->wqueue = mfree(b->wqueue); b->wqueue_allocated = 0; } @@ -105,6 +107,7 @@ static void bus_free(sd_bus *b) { assert(b); assert(!b->track_queue); + assert(!b->tracks); b->state = BUS_CLOSED; @@ -220,8 +223,8 @@ _public_ int sd_bus_set_address(sd_bus *bus, const char *address) { _public_ int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd) { assert_return(bus, -EINVAL); assert_return(bus->state == BUS_UNSET, -EPERM); - assert_return(input_fd >= 0, -EINVAL); - assert_return(output_fd >= 0, -EINVAL); + assert_return(input_fd >= 0, -EBADF); + assert_return(output_fd >= 0, -EBADF); assert_return(!bus_pid_changed(bus), -ECHILD); bus->input_fd = input_fd; @@ -311,10 +314,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - if (b) - bus->creds_mask |= mask; - else - bus->creds_mask &= ~mask; + SET_FLAG(bus->creds_mask, mask, b); /* The well knowns we need unconditionally, so that matches can work */ bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; @@ -415,7 +415,7 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e } static int bus_send_hello(sd_bus *bus) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -528,7 +528,7 @@ static void skip_address_key(const char **p) { *p += strcspn(*p, ","); if (**p == ',') - (*p) ++; + (*p)++; } static int parse_unix_address(sd_bus *b, const char **p, char **guid) { @@ -693,7 +693,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) { goto fail; } - (*p) ++; + (*p)++; if (ul >= n_argv) { if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) { @@ -825,8 +825,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) b->machine = machine; machine = NULL; } else { - free(b->machine); - b->machine = NULL; + b->machine = mfree(b->machine); } if (pid) { @@ -838,7 +837,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) b->sockaddr.un.sun_family = AF_UNIX; strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path)); - b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket"); + b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un); return 0; } @@ -885,8 +884,7 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid b->machine = machine; machine = NULL; } else { - free(b->machine); - b->machine = NULL; + b->machine = mfree(b->machine); } if (pid) { @@ -896,10 +894,9 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid } else b->nspid = 0; - free(b->kernel); - b->kernel = strdup("/sys/fs/kdbus/0-system/bus"); - if (!b->kernel) - return -ENOMEM; + r = free_and_strdup(&b->kernel, "/sys/fs/kdbus/0-system/bus"); + if (r < 0) + return r; return 0; } @@ -909,15 +906,11 @@ static void bus_reset_parsed_address(sd_bus *b) { zero(b->sockaddr); b->sockaddr_size = 0; - strv_free(b->exec_argv); - free(b->exec_path); - b->exec_path = NULL; - b->exec_argv = NULL; + b->exec_argv = strv_free(b->exec_argv); + b->exec_path = mfree(b->exec_path); b->server_id = SD_ID128_NULL; - free(b->kernel); - b->kernel = NULL; - free(b->machine); - b->machine = NULL; + b->kernel = mfree(b->kernel); + b->machine = mfree(b->machine); b->nspid = 0; } @@ -1012,6 +1005,8 @@ static int bus_parse_next_address(sd_bus *b) { } static int bus_start_address(sd_bus *b) { + bool container_kdbus_available = false; + bool kdbus_available = false; int r; assert(b); @@ -1021,17 +1016,40 @@ static int bus_start_address(sd_bus *b) { bus_close_fds(b); + /* + * Usually, if you provide multiple different bus-addresses, we + * try all of them in order. We use the first one that + * succeeds. However, if you mix kernel and unix addresses, we + * never try unix-addresses if a previous kernel address was + * tried and kdbus was available. This is required to prevent + * clients to fallback to the bus-proxy if kdbus is available + * but failed (eg., too many connections). + */ + if (b->exec_path) r = bus_socket_exec(b); - else if ((b->nspid > 0 || b->machine) && b->kernel) + else if ((b->nspid > 0 || b->machine) && b->kernel) { r = bus_container_connect_kernel(b); - else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) - r = bus_container_connect_socket(b); - else if (b->kernel) + if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT)) + container_kdbus_available = true; + + } else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) { + if (!container_kdbus_available) + r = bus_container_connect_socket(b); + else + skipped = true; + + } else if (b->kernel) { r = bus_kernel_connect(b); - else if (b->sockaddr.sa.sa_family != AF_UNSPEC) - r = bus_socket_connect(b); - else + if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT)) + kdbus_available = true; + + } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) { + if (!kdbus_available) + r = bus_socket_connect(b); + else + skipped = true; + } else skipped = true; if (!skipped) { @@ -1224,6 +1242,8 @@ fail: int bus_set_address_user(sd_bus *b) { const char *e; + uid_t uid; + int r; assert(b); @@ -1231,6 +1251,10 @@ int bus_set_address_user(sd_bus *b) { if (e) return sd_bus_set_address(b, e); + r = cg_pid_get_owner_uid(0, &uid); + if (r < 0) + uid = getuid(); + e = secure_getenv("XDG_RUNTIME_DIR"); if (e) { _cleanup_free_ char *ee = NULL; @@ -1239,9 +1263,9 @@ int bus_set_address_user(sd_bus *b) { if (!ee) return -ENOMEM; - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee); + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee); } else - (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()); + (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid); if (!b->address) return -ENOMEM; @@ -1452,7 +1476,9 @@ static void bus_enter_closing(sd_bus *bus) { } _public_ sd_bus *sd_bus_ref(sd_bus *bus) { - assert_return(bus, NULL); + + if (!bus) + return NULL; assert_se(REFCNT_INC(bus->n_ref) >= 2); @@ -1640,7 +1666,7 @@ static int dispatch_wqueue(sd_bus *bus) { * it got full, then all bets are off * anyway. */ - bus->wqueue_size --; + bus->wqueue_size--; sd_bus_message_unref(bus->wqueue[0]); memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size); bus->windex = 0; @@ -1689,7 +1715,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd /* Dispatch a queued message */ *m = bus->rqueue[0]; - bus->rqueue_size --; + bus->rqueue_size--; memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size); return 1; } @@ -1706,7 +1732,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd } static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bool hint_sync_call) { - _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); int r; assert_return(m, -EINVAL); @@ -1753,7 +1779,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, r = bus_write_message(bus, m, hint_sync_call, &idx); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); return -ECONNRESET; } @@ -1781,7 +1807,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1)) return -ENOMEM; - bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m); + bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m); } finish: @@ -1854,8 +1880,8 @@ _public_ int sd_bus_call_async( void *userdata, uint64_t usec) { - _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); - _cleanup_bus_slot_unref_ sd_bus_slot *s = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *s = NULL; int r; assert_return(m, -EINVAL); @@ -1953,43 +1979,45 @@ _public_ int sd_bus_call( sd_bus_error *error, sd_bus_message **reply) { - _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); usec_t timeout; uint64_t cookie; unsigned i; int r; - assert_return(m, -EINVAL); - assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL); - assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL); - assert_return(!bus_error_is_dirty(error), -EINVAL); + bus_assert_return(m, -EINVAL, error); + bus_assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL, error); + bus_assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL, error); + bus_assert_return(!bus_error_is_dirty(error), -EINVAL, error); if (!bus) bus = m->bus; - assert_return(!bus_pid_changed(bus), -ECHILD); - assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS); + bus_assert_return(!bus_pid_changed(bus), -ECHILD, error); + bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error); - if (!BUS_IS_OPEN(bus->state)) - return -ENOTCONN; + if (!BUS_IS_OPEN(bus->state)) { + r = -ENOTCONN; + goto fail; + } r = bus_ensure_running(bus); if (r < 0) - return r; + goto fail; i = bus->rqueue_size; r = bus_seal_message(bus, m, usec); if (r < 0) - return r; + goto fail; r = bus_remarshal_message(bus, &m); if (r < 0) - return r; + goto fail; r = bus_send_internal(bus, m, &cookie, true); if (r < 0) - return r; + goto fail; timeout = calc_elapse(m->timeout); @@ -2020,14 +2048,17 @@ _public_ int sd_bus_call( } r = sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry."); + sd_bus_message_unref(incoming); + return r; - } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) + } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) { r = sd_bus_error_copy(error, &incoming->error); - else + sd_bus_message_unref(incoming); + return r; + } else { r = -EIO; - - sd_bus_message_unref(incoming); - return r; + goto fail; + } } else if (BUS_MESSAGE_COOKIE(incoming) == cookie && bus->unique_name && @@ -2043,7 +2074,8 @@ _public_ int sd_bus_call( * immediately. */ sd_bus_message_unref(incoming); - return -ELOOP; + r = -ELOOP; + goto fail; } /* Try to read more, right-away */ @@ -2052,12 +2084,12 @@ _public_ int sd_bus_call( r = bus_read_message(bus, false, 0); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); - return -ECONNRESET; + r = -ECONNRESET; } - return r; + goto fail; } if (r > 0) continue; @@ -2066,8 +2098,10 @@ _public_ int sd_bus_call( usec_t n; n = now(CLOCK_MONOTONIC); - if (n >= timeout) - return -ETIMEDOUT; + if (n >= timeout) { + r = -ETIMEDOUT; + goto fail; + } left = timeout - n; } else @@ -2075,20 +2109,25 @@ _public_ int sd_bus_call( r = bus_poll(bus, true, left); if (r < 0) - return r; - if (r == 0) - return -ETIMEDOUT; + goto fail; + if (r == 0) { + r = -ETIMEDOUT; + goto fail; + } r = dispatch_wqueue(bus); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); - return -ECONNRESET; + r = -ECONNRESET; } - return r; + goto fail; } } + +fail: + return sd_bus_error_set_errno(error, r); } _public_ int sd_bus_get_fd(sd_bus *bus) { @@ -2179,8 +2218,8 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { } static int process_timeout(sd_bus *bus) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message* m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* m = NULL; struct reply_callback *c; sd_bus_slot *slot; usec_t n; @@ -2216,7 +2255,7 @@ static int process_timeout(sd_bus *bus) { slot = container_of(c, sd_bus_slot, reply_callback); - bus->iteration_counter ++; + bus->iteration_counter++; bus->current_message = m; bus->current_slot = sd_bus_slot_ref(slot); @@ -2261,8 +2300,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) { } static int process_reply(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *synthetic_reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; struct reply_callback *c; sd_bus_slot *slot; int r; @@ -2341,7 +2380,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { } static int process_filter(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; struct filter_callback *l; int r; @@ -2407,7 +2446,7 @@ static int process_match(sd_bus *bus, sd_bus_message *m) { } static int process_builtin(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(bus); @@ -2539,7 +2578,7 @@ static int dispatch_track(sd_bus *bus) { } static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -2602,62 +2641,101 @@ null_message: return r; } -static int process_closing(sd_bus *bus, sd_bus_message **ret) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - struct reply_callback *c; +static int bus_exit_now(sd_bus *bus) { + assert(bus); + + /* Exit due to close, if this is requested. If this is bus object is attached to an event source, invokes + * sd_event_exit(), otherwise invokes libc exit(). */ + + if (bus->exited) /* did we already exit? */ + return 0; + if (!bus->exit_triggered) /* was the exit condition triggered? */ + return 0; + if (!bus->exit_on_disconnect) /* Shall we actually exit on disconnection? */ + return 0; + + bus->exited = true; /* never exit more than once */ + + log_debug("Bus connection disconnected, exiting."); + + if (bus->event) + return sd_event_exit(bus->event, EXIT_FAILURE); + else + exit(EXIT_FAILURE); + + assert_not_reached("exit() didn't exit?"); +} + +static int process_closing_reply_callback(sd_bus *bus, struct reply_callback *c) { + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + sd_bus_slot *slot; int r; assert(bus); - assert(bus->state == BUS_CLOSING); + assert(c); - c = ordered_hashmap_first(bus->reply_callbacks); - if (c) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - sd_bus_slot *slot; + r = bus_message_new_synthetic_error( + bus, + c->cookie, + &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"), + &m); + if (r < 0) + return r; - /* First, fail all outstanding method calls */ - r = bus_message_new_synthetic_error( - bus, - c->cookie, - &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"), - &m); - if (r < 0) - return r; + r = bus_seal_synthetic_message(bus, m); + if (r < 0) + return r; - r = bus_seal_synthetic_message(bus, m); - if (r < 0) - return r; + if (c->timeout != 0) { + prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); + c->timeout = 0; + } - if (c->timeout != 0) { - prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx); - c->timeout = 0; - } + ordered_hashmap_remove(bus->reply_callbacks, &c->cookie); + c->cookie = 0; - ordered_hashmap_remove(bus->reply_callbacks, &c->cookie); - c->cookie = 0; + slot = container_of(c, sd_bus_slot, reply_callback); - slot = container_of(c, sd_bus_slot, reply_callback); + bus->iteration_counter++; - bus->iteration_counter++; + bus->current_message = m; + bus->current_slot = sd_bus_slot_ref(slot); + bus->current_handler = c->callback; + bus->current_userdata = slot->userdata; + r = c->callback(m, slot->userdata, &error_buffer); + bus->current_userdata = NULL; + bus->current_handler = NULL; + bus->current_slot = NULL; + bus->current_message = NULL; - bus->current_message = m; - bus->current_slot = sd_bus_slot_ref(slot); - bus->current_handler = c->callback; - bus->current_userdata = slot->userdata; - r = c->callback(m, slot->userdata, &error_buffer); - bus->current_userdata = NULL; - bus->current_handler = NULL; - bus->current_slot = NULL; - bus->current_message = NULL; + if (slot->floating) { + bus_slot_disconnect(slot); + sd_bus_slot_unref(slot); + } - if (slot->floating) { - bus_slot_disconnect(slot); - sd_bus_slot_unref(slot); - } + sd_bus_slot_unref(slot); - sd_bus_slot_unref(slot); + return bus_maybe_reply_error(m, r, &error_buffer); +} + +static int process_closing(sd_bus *bus, sd_bus_message **ret) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + struct reply_callback *c; + int r; + + assert(bus); + assert(bus->state == BUS_CLOSING); + + /* First, fail all outstanding method calls */ + c = ordered_hashmap_first(bus->reply_callbacks); + if (c) + return process_closing_reply_callback(bus, c); - return bus_maybe_reply_error(m, r, &error_buffer); + /* Then, fake-drop all remaining bus tracking references */ + if (bus->tracks) { + bus_track_close(bus->tracks); + return 1; } /* Then, synthesize a Disconnected message */ @@ -2689,6 +2767,10 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { if (r != 0) goto finish; + /* Nothing else to do, exit now, if the condition holds */ + bus->exit_triggered = true; + (void) bus_exit_now(bus); + if (ret) { *ret = m; m = NULL; @@ -2728,7 +2810,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_OPENING: r = bus_socket_process_opening(bus); - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = 1; } else if (r < 0) @@ -2739,7 +2821,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_AUTHENTICATING: r = bus_socket_process_authenticating(bus); - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = 1; } else if (r < 0) @@ -2753,7 +2835,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit case BUS_RUNNING: case BUS_HELLO: r = process_running(bus, hint_priority, priority, ret); - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); r = 1; @@ -2876,7 +2958,7 @@ _public_ int sd_bus_flush(sd_bus *bus) { for (;;) { r = dispatch_wqueue(bus); if (r < 0) { - if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) { + if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) { bus_enter_closing(bus); return -ECONNRESET; } @@ -3316,14 +3398,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); } @@ -3350,7 +3429,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); } @@ -3422,6 +3500,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; @@ -3573,3 +3816,38 @@ _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); +} + +_public_ int sd_bus_set_exit_on_disconnect(sd_bus *bus, int b) { + assert_return(bus, -EINVAL); + + /* Turns on exit-on-disconnect, and triggers it immediately if the bus connection was already + * disconnected. Note that this is triggered exclusively on disconnections triggered by the server side, never + * from the client side. */ + bus->exit_on_disconnect = b; + + /* If the exit condition was triggered already, exit immediately. */ + return bus_exit_now(bus); +} + +_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) { + assert_return(bus, -EINVAL); + + return bus->exit_on_disconnect; +} diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c index d14110aa04..56ac2ab3dd 100644 --- a/src/libsystemd/sd-bus/test-bus-benchmark.c +++ b/src/libsystemd/sd-bus/test-bus-benchmark.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,14 +19,16 @@ #include <sys/wait.h> -#include "def.h" -#include "util.h" -#include "time-util.h" - #include "sd-bus.h" -#include "bus-kernel.h" + +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-kernel.h" #include "bus-util.h" +#include "def.h" +#include "fd-util.h" +#include "time-util.h" +#include "util.h" #define MAX_SIZE (2*1024*1024) @@ -44,7 +44,7 @@ static void server(sd_bus *b, size_t *result) { int r; for (;;) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_process(b, &m); assert_se(r >= 0); @@ -78,7 +78,7 @@ static void server(sd_bus *b, size_t *result) { } static void transaction(sd_bus *b, size_t sz, const char *server_name) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; uint8_t *p; assert_se(sd_bus_message_new_method_call(b, &m, server_name, "/", "benchmark.server", "Work") >= 0); @@ -90,7 +90,7 @@ static void transaction(sd_bus *b, size_t sz, const char *server_name) { } static void client_bisect(const char *address, const char *server_name) { - _cleanup_bus_message_unref_ sd_bus_message *x = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *x = NULL; size_t lsize, rsize, csize; sd_bus *b; int r; @@ -164,7 +164,7 @@ static void client_bisect(const char *address, const char *server_name) { } static void client_chart(Type type, const char *address, const char *server_name, int fd) { - _cleanup_bus_message_unref_ sd_bus_message *x = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *x = NULL; size_t csize; sd_bus *b; int r; diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 754335b5e7..fc60830059 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,21 +17,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <fcntl.h> #include <pthread.h> +#include <stdlib.h> #include <unistd.h> -#include <fcntl.h> - -#include "log.h" -#include "util.h" -#include "macro.h" -#include "formats-util.h" #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "bus-match.h" #include "bus-internal.h" +#include "bus-match.h" #include "bus-util.h" +#include "fd-util.h" +#include "formats-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m))); @@ -119,9 +119,7 @@ static int server_init(sd_bus **_bus) { return 0; fail: - if (bus) - sd_bus_unref(bus); - + sd_bus_unref(bus); return r; } @@ -130,7 +128,7 @@ static int server(sd_bus *bus) { bool client1_gone = false, client2_gone = false; while (!client1_gone || !client2_gone) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; pid_t pid = 0; const char *label = NULL; @@ -261,9 +259,9 @@ fail: } static void* client1(void*p) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *hello; int r; _cleanup_close_pair_ int pp[2] = { -1, -1 }; @@ -331,7 +329,7 @@ static void* client1(void*p) { finish: if (bus) { - _cleanup_bus_message_unref_ sd_bus_message *q; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *q; r = sd_bus_message_new_method_call( bus, @@ -353,16 +351,16 @@ finish: static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { bool *x = userdata; - log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m))); + log_error_errno(sd_bus_message_get_errno(m), "Quit callback: %m"); *x = 1; return 1; } static void* client2(void*p) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool quit = false; const char *mid; int r; @@ -499,7 +497,7 @@ static void* client2(void*p) { finish: if (bus) { - _cleanup_bus_message_unref_ sd_bus_message *q; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *q; r = sd_bus_message_new_method_call( bus, diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index f586880593..250a5b2908 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,20 +20,21 @@ #include <stdio.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-internal.h" #include "bus-message.h" +#include "bus-util.h" #include "refcnt.h" static void test_bus_new(void) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; assert_se(sd_bus_new(&bus) == 0); printf("after new: refcount %u\n", REFCNT_GET(bus->n_ref)); } static int test_bus_open(void) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; r = sd_bus_open_system(&bus); @@ -50,7 +49,7 @@ static int test_bus_open(void) { static void test_bus_new_method_call(void) { sd_bus *bus = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; assert_se(sd_bus_open_system(&bus) >= 0); @@ -58,13 +57,13 @@ static void test_bus_new_method_call(void) { printf("after message_new_method_call: refcount %u\n", REFCNT_GET(bus->n_ref)); - sd_bus_unref(bus); - printf("after bus_unref: refcount %u\n", m->n_ref); + sd_bus_flush_close_unref(bus); + printf("after bus_flush_close_unref: refcount %u\n", m->n_ref); } static void test_bus_new_signal(void) { sd_bus *bus = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; assert_se(sd_bus_open_system(&bus) >= 0); @@ -72,8 +71,8 @@ static void test_bus_new_signal(void) { printf("after message_new_signal: refcount %u\n", REFCNT_GET(bus->n_ref)); - sd_bus_unref(bus); - printf("after bus_unref: refcount %u\n", m->n_ref); + sd_bus_flush_close_unref(bus); + printf("after bus_flush_close_unref: refcount %u\n", m->n_ref); } int main(int argc, char **argv) { diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index edd5033db2..6fdcfa4128 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,14 +18,26 @@ ***/ #include "sd-bus.h" + #include "bus-dump.h" #include "bus-util.h" +#include "cgroup-util.h" int main(int argc, char *argv[]) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; int r; + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + + if (cg_all_unified() == -ENOMEDIUM) { + log_info("Skipping test: /sys/fs/cgroup/ not available"); + return EXIT_TEST_SKIP; + } + r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL); + log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG, r, "sd_bus_creds_new_from_pid: %m"); assert_se(r >= 0); bus_creds_dump(creds, NULL, true); diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 5753c04b0e..66a3874f10 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,13 +18,14 @@ ***/ #include "sd-bus.h" + +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-util.h" #include "errno-list.h" -#include "bus-common-errors.h" static void test_error(void) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error"); const sd_bus_error temporarily_const_error = { .name = SD_BUS_ERROR_ACCESS_DENIED, @@ -43,7 +42,15 @@ static void test_error(void) { assert_se(sd_bus_error_is_set(&error)); sd_bus_error_free(&error); + /* Check with no error */ + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_setf(&error, NULL, "yyy %i", -1) == 0); + assert_se(error.name == NULL); + assert_se(error.message == NULL); + assert_se(!sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(sd_bus_error_get_errno(&error) == 0); assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_setf(&error, SD_BUS_ERROR_FILE_NOT_FOUND, "yyy %i", -1) == -ENOENT); assert_se(streq(error.name, SD_BUS_ERROR_FILE_NOT_FOUND)); assert_se(streq(error.message, "yyy -1")); @@ -111,6 +118,16 @@ static void test_error(void) { assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR)); assert_se(sd_bus_error_get_errno(&error) == EIO); assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + /* Check with no error */ + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_errnof(&error, 0, "Waldi %c", 'X') == 0); + assert_se(error.name == NULL); + assert_se(error.message == NULL); + assert_se(!sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR)); + assert_se(sd_bus_error_get_errno(&error) == 0); + assert_se(!sd_bus_error_is_set(&error)); } extern const sd_bus_error_map __start_BUS_ERROR_MAP[]; @@ -129,7 +146,7 @@ static void dump_mapping_table(void) { } printf("%s -> %i/%s\n", strna(m->name), m->code, strna(errno_to_name(m->code))); - m ++; + m++; } printf("---------------------------\n"); } @@ -166,6 +183,16 @@ static const sd_bus_error_map test_errors4[] = { SD_BUS_ERROR_MAP_END }; +static const sd_bus_error_map test_errors_bad1[] = { + SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-1", 0), + SD_BUS_ERROR_MAP_END +}; + +static const sd_bus_error_map test_errors_bad2[] = { + SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-1", -1), + SD_BUS_ERROR_MAP_END +}; + static void test_errno_mapping_custom(void) { assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error", NULL) == -5); assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52); @@ -189,6 +216,9 @@ static void test_errno_mapping_custom(void) { assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-y", NULL) == -EIO); assert_se(sd_bus_error_set(NULL, BUS_ERROR_NO_SUCH_UNIT, NULL) == -ENOENT); + + assert_se(sd_bus_error_add_map(test_errors_bad1) == -EINVAL); + assert_se(sd_bus_error_add_map(test_errors_bad2) == -EINVAL); } int main(int argc, char *argv[]) { diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index 9b7dd2e499..83f114a0fe 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,14 +21,16 @@ #include <glib.h> #endif -#include "util.h" -#include "macro.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-gvariant.h" -#include "bus-util.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-dump.h" +#include "bus-util.h" +#include "macro.h" +#include "util.h" static void test_bus_gvariant_is_fixed_size(void) { assert_se(bus_gvariant_is_fixed_size("") > 0); @@ -59,7 +59,7 @@ static void test_bus_gvariant_is_fixed_size(void) { static void test_bus_gvariant_get_size(void) { assert_se(bus_gvariant_get_size("") == 0); - assert_se(bus_gvariant_get_size("()") == 0); + assert_se(bus_gvariant_get_size("()") == 1); assert_se(bus_gvariant_get_size("y") == 1); assert_se(bus_gvariant_get_size("u") == 4); assert_se(bus_gvariant_get_size("b") == 1); @@ -131,8 +131,8 @@ static void test_bus_gvariant_get_alignment(void) { } static void test_marshal(void) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ void *blob; size_t sz; int r; diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c index b2caa02870..4425cfae26 100644 --- a/src/libsystemd/sd-bus/test-bus-introspect.c +++ b/src/libsystemd/sd-bus/test-bus-introspect.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" #include "bus-introspect.h" +#include "log.h" static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { return -EINVAL; @@ -41,7 +39,7 @@ static const sd_bus_vtable vtable[] = { SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED), SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), - SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EXPLICIT), SD_BUS_VTABLE_END }; diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c index 90eb1f2a33..eb6179d7d2 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-kernel.h" #include "bus-util.h" +#include "fd-util.h" +#include "log.h" +#include "util.h" static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { int *found = userdata; @@ -45,7 +45,7 @@ static void test_one( _cleanup_close_ int bus_ref = -1; _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus *a, *b; int r, found = 0; @@ -108,8 +108,10 @@ int main(int argc, char *argv[]) { test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Pi_ep'", false); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foobar'", true); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foo_bar'", false); - test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", false); test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foo_bar'", false); + test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foobar'", true); + test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foo_bar'", false); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true); test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false); diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index 6506eaab2e..2214817312 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,19 +19,21 @@ #include <fcntl.h> -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-kernel.h" #include "bus-util.h" -#include "bus-dump.h" +#include "fd-util.h" +#include "log.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int bus_ref = -1; _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *bname = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *ua = NULL, *ub = NULL, *the_string = NULL; sd_bus *a, *b; int r, pipe_fds[2]; diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index 59deaea89f..a28cc5b79e 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <math.h> +#include <stdlib.h> #ifdef HAVE_GLIB #include <gio/gio.h> @@ -30,14 +28,17 @@ #include <dbus/dbus.h> #endif -#include "log.h" -#include "util.h" - #include "sd-bus.h" -#include "bus-message.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-dump.h" #include "bus-label.h" +#include "bus-message.h" +#include "bus-util.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "log.h" +#include "util.h" static void test_bus_path_encode_unique(void) { _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL; @@ -66,6 +67,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; @@ -90,7 +121,7 @@ static void test_bus_label_escape(void) { } int main(int argc, char *argv[]) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *copy = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *copy = NULL; int r, boolean; const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature; uint8_t u, v; @@ -102,7 +133,7 @@ int main(int argc, char *argv[]) { _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL; _cleanup_fclose_ FILE *ms = NULL; size_t first_size = 0, second_size = 0, third_size = 0; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; double dbl; uint64_t u64; @@ -134,6 +165,9 @@ int main(int argc, char *argv[]) { r = sd_bus_message_append(m, "y(ty)y(yt)y", 8, 777ULL, 7, 9, 77, 7777ULL, 10); assert_se(r >= 0); + r = sd_bus_message_append(m, "()"); + assert_se(r >= 0); + r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3"); assert_se(r >= 0); @@ -210,6 +244,8 @@ int main(int argc, char *argv[]) { log_error("%s", error.message); else dbus_message_unref(w); + + dbus_error_free(&error); } #endif @@ -271,6 +307,9 @@ int main(int argc, char *argv[]) { assert_se(r > 0); assert_se(v == 10); + r = sd_bus_message_read(m, "()"); + assert_se(r > 0); + r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d); assert_se(r > 0); assert_se(boolean); @@ -350,7 +389,7 @@ int main(int argc, char *argv[]) { assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0); - r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y"); + r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y()"); assert_se(r >= 0); assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0); @@ -387,6 +426,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; } diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index 83cb5c62c2..29c4529f95 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,13 +17,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" -#include "macro.h" - #include "bus-match.h" #include "bus-message.h" -#include "bus-util.h" #include "bus-slot.h" +#include "bus-util.h" +#include "log.h" +#include "macro.h" static bool mask[32]; @@ -91,8 +88,8 @@ int main(int argc, char *argv[]) { .type = BUS_MATCH_ROOT, }; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; enum bus_match_node_type i; sd_bus_slot slots[19]; int r; @@ -115,10 +112,10 @@ int main(int argc, char *argv[]) { assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0); assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0); assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0); - assert_se(match_add(slots, &root, "arg4='pi'", 15) >= 0); - assert_se(match_add(slots, &root, "arg4='pa'", 16) >= 0); - assert_se(match_add(slots, &root, "arg4='po'", 17) >= 0); - assert_se(match_add(slots, &root, "arg4='pu'", 18) >= 0); + assert_se(match_add(slots, &root, "arg4has='pi'", 15) >= 0); + assert_se(match_add(slots, &root, "arg4has='pa'", 16) >= 0); + assert_se(match_add(slots, &root, "arg4has='po'", 17) >= 0); + assert_se(match_add(slots, &root, "arg4='pi'", 18) >= 0); bus_match_dump(&root, 0); diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 1db67ecfac..f11cafd888 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,19 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <pthread.h> - -#include "log.h" -#include "util.h" -#include "macro.h" -#include "strv.h" +#include <stdlib.h> #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "bus-dump.h" +#include "log.h" +#include "macro.h" +#include "strv.h" +#include "util.h" struct context { int fds[2]; @@ -115,13 +114,14 @@ static int set_handler(sd_bus *bus, const char *path, const char *interface, con static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { _cleanup_free_ char *s = NULL; + const char *x; int r; assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0); r = sd_bus_message_append(reply, "s", s); assert_se(r >= 0); - assert_se(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0); + assert_se(x = startswith(path, "/value/")); assert_se(PTR_TO_UINT(userdata) == 30); @@ -153,7 +153,7 @@ static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error) static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0); + assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -164,7 +164,7 @@ static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0); + assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -175,7 +175,7 @@ static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_err static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), m->path) >= 0); + assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), "/value/a/x") >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -186,7 +186,7 @@ static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *er static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) { int r; - assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), m->path) >= 0); + assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), "/value/a/x") >= 0); r = sd_bus_reply_method_return(m, NULL); assert_se(r >= 0); @@ -217,6 +217,7 @@ static const sd_bus_vtable vtable2[] = { SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0), + SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL, offsetof(struct context, something), SD_BUS_VTABLE_PROPERTY_EXPLICIT|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), SD_BUS_VTABLE_END }; @@ -228,6 +229,14 @@ static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, ch return 1; } +static int enumerator2_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + + if (object_path_startswith("/value/a", path)) + assert_se(*nodes = strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL)); + + return 1; +} + static void *server(void *p) { struct context *c = p; sd_bus *bus = NULL; @@ -246,7 +255,9 @@ static void *server(void *p) { assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0); assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0); assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0); + assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value/a", enumerator2_callback, NULL) >= 0); assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0); + assert_se(sd_bus_add_object_manager(bus, NULL, "/value/a") >= 0); assert_se(sd_bus_start(bus) >= 0); @@ -284,9 +295,9 @@ fail: } static int client(struct context *c) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *s; int r; diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c deleted file mode 100644 index 369c2f331c..0000000000 --- a/src/libsystemd/sd-bus/test-bus-proxy.c +++ /dev/null @@ -1,109 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2015 David Herrmann <dh.herrmann@gmail.com> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> - -#include "util.h" -#include "log.h" - -#include "sd-bus.h" -#include "bus-kernel.h" -#include "bus-util.h" -#include "bus-dump.h" - -typedef struct { - const char *sender; - int matched_acquired; -} TestProxyMatch; - -static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) { - TestProxyMatch *match = userdata; - const char *name; - int r; - - r = sd_bus_message_read(m, "s", &name); - assert_se(r >= 0); - - if (!streq_ptr(match->sender, name)) - return 0; - - ++match->matched_acquired; - return 1; -} - -static void test_proxy_matched(void) { - _cleanup_bus_flush_close_unref_ sd_bus *a = NULL; - TestProxyMatch match = {}; - int r; - - /* open bus 'a' */ - - r = sd_bus_new(&a); - assert_se(r >= 0); - - r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket"); - assert_se(r >= 0); - - r = sd_bus_set_bus_client(a, true); - assert_se(r >= 0); - - r = sd_bus_start(a); - assert_se(r >= 0); - - r = sd_bus_add_match(a, NULL, - "type='signal'," - "member='NameAcquired'", - test_proxy_acquired, &match); - assert_se(r >= 0); - - r = sd_bus_get_unique_name(a, &match.sender); - assert_se(r >= 0); - - /* barrier to guarantee proxy/dbus-daemon handled the previous data */ - r = sd_bus_call_method(a, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "GetId", - NULL, NULL, NULL); - assert_se(r >= 0); - - /* now we can be sure the Name* signals were sent */ - do { - r = sd_bus_process(a, NULL); - } while (r > 0); - assert_se(r == 0); - - assert_se(match.matched_acquired == 1); -} - -int main(int argc, char **argv) { - if (access("/var/run/dbus/system_bus_socket", F_OK) < 0) - return EXIT_TEST_SKIP; - - log_parse_environment(); - - test_proxy_matched(); - - return EXIT_SUCCESS; -} diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c index 080d8eddb7..b6272efc30 100644 --- a/src/libsystemd/sd-bus/test-bus-server.c +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,16 +17,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <pthread.h> - -#include "log.h" -#include "util.h" -#include "macro.h" +#include <stdlib.h> #include "sd-bus.h" + #include "bus-internal.h" #include "bus-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" struct context { int fds[2]; @@ -57,7 +55,7 @@ static void *server(void *p) { assert_se(sd_bus_start(bus) >= 0); while (!quit) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; r = sd_bus_process(bus, &m); if (r < 0) { @@ -124,8 +122,8 @@ fail: } static int client(struct context *c) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; int r; diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c index 17c6188ca0..4f4fd093bf 100644 --- a/src/libsystemd/sd-bus/test-bus-signature.c +++ b/src/libsystemd/sd-bus/test-bus-signature.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "log.h" -#include "bus-signature.h" #include "bus-internal.h" +#include "bus-signature.h" +#include "log.h" +#include "string-util.h" int main(int argc, char *argv[]) { char prefix[256]; diff --git a/src/libsystemd/sd-bus/test-bus-track.c b/src/libsystemd/sd-bus/test-bus-track.c new file mode 100644 index 0000000000..4beb61f05a --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-track.c @@ -0,0 +1,113 @@ +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sd-bus.h> + +#include "macro.h" + +static bool track_cb_called_x = false; +static bool track_cb_called_y = false; + +static int track_cb_x(sd_bus_track *t, void *userdata) { + + log_error("TRACK CB X"); + + assert_se(!track_cb_called_x); + track_cb_called_x = true; + + /* This means b's name disappeared. Let's now disconnect, to make sure the track handling on disconnect works + * as it should. */ + + assert_se(shutdown(sd_bus_get_fd(sd_bus_track_get_bus(t)), SHUT_RDWR) >= 0); + return 1; +} + +static int track_cb_y(sd_bus_track *t, void *userdata) { + int r; + + log_error("TRACK CB Y"); + + assert_se(!track_cb_called_y); + track_cb_called_y = true; + + /* We got disconnected, let's close everything */ + + r = sd_event_exit(sd_bus_get_event(sd_bus_track_get_bus(t)), EXIT_SUCCESS); + assert_se(r >= 0); + + return 0; +} + +int main(int argc, char *argv[]) { + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; + const char *unique; + int r; + + r = sd_event_default(&event); + assert_se(r >= 0); + + r = sd_bus_open_system(&a); + if (IN_SET(r, -ECONNREFUSED, -ENOENT)) { + log_info("Failed to connect to bus, skipping tests."); + return EXIT_TEST_SKIP; + } + assert_se(r >= 0); + + r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL); + assert_se(r >= 0); + + r = sd_bus_open_system(&b); + assert_se(r >= 0); + + r = sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL); + assert_se(r >= 0); + + /* Watch b's name from a */ + r = sd_bus_track_new(a, &x, track_cb_x, NULL); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(b, &unique); + assert_se(r >= 0); + + r = sd_bus_track_add_name(x, unique); + assert_se(r >= 0); + + /* Watch's a's own name from a */ + r = sd_bus_track_new(a, &y, track_cb_y, NULL); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(a, &unique); + assert_se(r >= 0); + + r = sd_bus_track_add_name(y, unique); + assert_se(r >= 0); + + /* Now make b's name disappear */ + sd_bus_close(b); + + r = sd_event_loop(event); + assert_se(r >= 0); + + assert_se(track_cb_called_x); + assert_se(track_cb_called_y); + + return 0; +} diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c index 2d062fc9b5..3380e8500a 100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,14 +19,17 @@ #include <sys/mman.h> -#include "util.h" -#include "log.h" -#include "memfd-util.h" - #include "sd-bus.h" -#include "bus-message.h" -#include "bus-kernel.h" + +#include "alloc-util.h" #include "bus-dump.h" +#include "bus-kernel.h" +#include "bus-message.h" +#include "fd-util.h" +#include "log.h" +#include "memfd-util.h" +#include "string-util.h" +#include "util.h" #define FIRST_ARRAY 17 #define SECOND_ARRAY 33 |