-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
/***
This file is part of systemd.
***/
#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 { \
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;
+#if 0 /// UNNEEDED by elogind
+static thread_local sd_bus *default_user_bus = NULL;
+#endif // 0
+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) {
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;
}
assert(b);
assert(!b->track_queue);
+ assert(!b->tracks);
b->state = BUS_CLOSED;
_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;
return 0;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]) {
char *p, **a;
return 0;
}
+#endif // 0
_public_ int sd_bus_set_bus_client(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
return 0;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_set_monitor(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
assert_return(bus->state == BUS_UNSET, -EPERM);
SET_FLAG(bus->hello_flags, KDBUS_HELLO_MONITOR, b);
return 0;
}
+#endif // 0
_public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
return 0;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
uint64_t new_flags;
assert_return(bus, -EINVAL);
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;
return 0;
}
+#endif // 0
_public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
assert_return(bus, -EINVAL);
return 0;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
assert_return(bus->state == BUS_UNSET, -EPERM);
return free_and_strdup(&bus->description, description);
}
+#endif // 0
_public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) {
assert_return(bus, -EINVAL);
return 0;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
return bus->allow_interactive_authorization;
}
+#endif // 0
static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
const char *s;
}
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);
*p += strcspn(*p, ",");
if (**p == ',')
- (*p) ++;
+ (*p)++;
}
static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
}
+ b->is_local = true;
+
return 0;
}
freeaddrinfo(result);
+ b->is_local = false;
+
return 0;
}
goto fail;
}
- (*p) ++;
+ (*p)++;
if (ul >= n_argv) {
if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) {
b->exec_path = path;
b->exec_argv = argv;
+
+ b->is_local = false;
+
return 0;
fail:
b->kernel = path;
path = NULL;
+ b->is_local = true;
+
return 0;
}
b->machine = machine;
machine = NULL;
} else {
- free(b->machine);
- b->machine = NULL;
+ b->machine = mfree(b->machine);
}
if (pid) {
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);
+ b->is_local = false;
return 0;
}
b->machine = machine;
machine = NULL;
} else {
- free(b->machine);
- b->machine = NULL;
+ b->machine = mfree(b->machine);
}
if (pid) {
} 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;
+
+ b->is_local = false;
return 0;
}
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;
}
}
static int bus_start_address(sd_bus *b) {
+ bool container_kdbus_available = false;
+ bool kdbus_available = false;
int r;
assert(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) {
if (e) {
if (streq(e, "system"))
return sd_bus_open_system(ret);
+#if 0 /// elogind does not support systemd units
else if (STR_IN_SET(e, "session", "user"))
return sd_bus_open_user(ret);
+#endif // 0
}
e = secure_getenv("DBUS_STARTER_ADDRESS");
if (!e) {
- return sd_bus_open_system(ret);
+#if 0 /// elogind does not support systemd units
+ if (cg_pid_get_owner_uid(0, NULL) >= 0)
+ return sd_bus_open_user(ret);
+ else
+#endif // 0
+ return sd_bus_open_system(ret);
}
r = sd_bus_new(&b);
/* We don't know whether the bus is trusted or not, so better
* be safe, and authenticate everything */
b->trusted = false;
+ b->is_local = false;
b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS;
b->trusted = false;
b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS;
+ b->is_local = true;
r = sd_bus_start(b);
if (r < 0)
return r;
}
+#if 0 /// elogind can not open/use a user bus
int bus_set_address_user(sd_bus *b) {
const char *e;
+ uid_t uid;
+ int r;
assert(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;
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;
return 0;
}
+#endif // 0
_public_ int sd_bus_open_user(sd_bus **ret) {
+#if 0 /// elogind does not support user buses
sd_bus *b;
int r;
/* We don't do any per-method access control on the user
* bus. */
b->trusted = true;
+ b->is_local = true;
r = sd_bus_start(b);
if (r < 0)
fail:
bus_free(b);
return r;
+#else
+ return sd_bus_open_system(ret);
+#endif // 0
}
int bus_set_address_system_remote(sd_bus *b, const char *host) {
return -ENOMEM;
}
- b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c, NULL);
+ b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c);
if (!b->address)
return -ENOMEM;
bus->bus_client = true;
bus->trusted = false;
bus->is_system = true;
+ bus->is_local = false;
r = sd_bus_start(bus);
if (r < 0)
if (!e)
return -ENOMEM;
- b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
+ b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e);
if (!b->address)
return -ENOMEM;
bus->bus_client = true;
bus->trusted = false;
bus->is_system = true;
+ bus->is_local = false;
r = sd_bus_start(bus);
if (r < 0)
}
_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);
return NULL;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_is_open(sd_bus *bus) {
assert_return(bus, -EINVAL);
return BUS_IS_OPEN(bus->state);
}
+#endif // 0
_public_ int sd_bus_can_send(sd_bus *bus, char type) {
int r;
return bus_type_is_valid(type);
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
int r;
*id = bus->server_id;
return 0;
}
+#endif // 0
static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
assert(b);
* 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;
/* 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;
}
}
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);
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;
}
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:
return bus_send_internal(bus, m, cookie, false);
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
int r;
return sd_bus_send(bus, m, cookie);
}
+#endif // 0
static usec_t calc_elapse(uint64_t usec) {
if (usec == (uint64_t) -1)
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);
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);
}
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 &&
* immediately. */
sd_bus_message_unref(incoming);
- return -ELOOP;
+ r = -ELOOP;
+ goto fail;
}
/* Try to read more, right-away */
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;
usec_t n;
n = now(CLOCK_MONOTONIC);
- if (n >= timeout)
- return -ETIMEDOUT;
+ if (n >= timeout) {
+ r = -ETIMEDOUT;
+ goto fail;
+ }
left = timeout - n;
} else
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);
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_get_fd(sd_bus *bus) {
assert_return(bus, -EINVAL);
return bus->input_fd;
}
+#endif // 0
_public_ int sd_bus_get_events(sd_bus *bus) {
int flags = 0;
}
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;
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);
}
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;
}
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;
}
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);
}
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);
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);
+}
- 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);
+
+ /* Then, fake-drop all remaining bus tracking references */
+ if (bus->tracks) {
+ bus_track_close(bus->tracks);
+ return 1;
}
/* Then, synthesize a Disconnected message */
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;
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)
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)
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;
return bus_process_internal(bus, false, 0, ret);
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_message **ret) {
return bus_process_internal(bus, true, priority, ret);
}
+#endif // 0
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
struct pollfd p[2] = {};
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;
}
}
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_add_filter(
sd_bus *bus,
sd_bus_slot **slot,
return 0;
}
+#endif // 0
_public_ int sd_bus_add_match(
sd_bus *bus,
return r;
}
+#if 0 /// UNNEEDED by elogind
int bus_remove_match_by_string(
sd_bus *bus,
const char *match,
return r;
}
+#endif // 0
bool bus_pid_changed(sd_bus *bus) {
assert(bus);
return bus->current_message;
}
+#if 0 /// UNNEEDED by elogind
_public_ sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus) {
assert_return(bus, NULL);
return bus->current_slot;
}
+#endif // 0
_public_ sd_bus_message_handler_t sd_bus_get_current_handler(sd_bus *bus) {
assert_return(bus, NULL);
}
_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) {
+#if 0 /// elogind does not support user buses
return bus_default(sd_bus_open_user, &default_user_bus, ret);
+#else
+ return sd_bus_default_system(ret);
+#endif // 0
}
_public_ int sd_bus_default(sd_bus **ret) {
if (e) {
if (streq(e, "system"))
return sd_bus_default_system(ret);
+#if 0 /// elogind does not support systemd units
else if (STR_IN_SET(e, "user", "session"))
return sd_bus_default_user(ret);
+#endif // 0
}
/* No type is specified, so we have not other option than to
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);
}
/* Finally, if nothing is set use the cached connection for
* the right scope */
- return sd_bus_default_system(ret);
+#if 0 /// elogind does not support systemd units
+ if (cg_pid_get_owner_uid(0, NULL) >= 0)
+ return sd_bus_default_user(ret);
+ else
+#endif // 0
+ return sd_bus_default_system(ret);
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_get_tid(sd_bus *b, pid_t *tid) {
assert_return(b, -EINVAL);
assert_return(tid, -EINVAL);
if (!e)
return -ENOMEM;
- ret = strjoin(prefix, "/", e, NULL);
+ ret = strjoin(prefix, "/", e);
if (!ret)
return -ENOMEM;
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;
*description = bus->description;
return 0;
}
+#endif // 0
int bus_get_root_path(sd_bus *bus) {
int r;
return r;
}
+#if 0 /// UNNEEDED by elogind
_public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
int r;
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);
+}
+#endif // 0
+
+_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);
+}
+
+#if 0 /// UNNEEDED by elogind
+_public_ int sd_bus_get_exit_on_disconnect(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+
+ return bus->exit_on_disconnect;
+}
+#endif // 0