#include "bus-objects.h"
#include "bus-util.h"
#include "bus-container.h"
+#include "bus-protocol.h"
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 void bus_close_fds(sd_bus *b) {
assert(b);
+ detach_io_events(b);
+
if (b->input_fd >= 0)
close_nointr_nofail(b->input_fd);
free(b->wqueue);
b->rqueue = b->wqueue = NULL;
+ b->rqueue_allocated = b->wqueue_allocated = 0;
b->rqueue_size = b->wqueue_size = 0;
}
free(b->address);
free(b->kernel);
free(b->machine);
+ free(b->fake_label);
+ free(b->cgroup_root);
free(b->exec_path);
strv_free(b->exec_argv);
r->n_ref = REFCNT_INIT;
r->input_fd = r->output_fd = -1;
r->message_version = 1;
+ r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
r->attach_flags |= KDBUS_ATTACH_NAMES;
r->original_pid = getpid();
/* We guarantee that wqueue always has space for at least one
* entry */
- r->wqueue = new(sd_bus_message*, 1);
- if (!r->wqueue) {
+ if (!GREEDY_REALLOC(r->wqueue, r->wqueue_allocated, 1)) {
free(r);
return -ENOMEM;
}
_public_ int sd_bus_negotiate_attach_creds(sd_bus *bus, uint64_t mask) {
assert_return(bus, -EINVAL);
- assert_return(mask <= _SD_BUS_CREDS_MAX, -EINVAL);
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL);
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- return kdbus_translate_attach_flags(mask, &bus->creds_mask);
+ /* The well knowns we need unconditionally, so that matches can work */
+ bus->creds_mask = mask | SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
+
+ return kdbus_translate_attach_flags(bus->creds_mask, &bus->creds_mask);
}
_public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
return 0;
}
+_public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
+ assert_return(bus, -EINVAL);
+ assert_return(bus->state == BUS_UNSET, -EPERM);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ bus->trusted = !!b;
+ return 0;
+}
+
static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
const char *s;
int r;
r = sd_bus_message_new_method_call(
bus,
"org.freedesktop.DBus",
- "/",
+ "/org/freedesktop/DBus",
"org.freedesktop.DBus",
"Hello",
&m);
if (r < 0)
return r;
- return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_serial);
+ return sd_bus_call_async(bus, m, hello_callback, NULL, 0, &bus->hello_cookie);
}
int bus_start_running(sd_bus *bus) {
}
static int parse_address_key(const char **p, const char *key, char **value) {
- size_t l, n = 0;
+ size_t l, n = 0, allocated = 0;
const char *a;
char *r = NULL;
a = *p;
while (*a != ';' && *a != ',' && *a != 0) {
- char c, *t;
+ char c;
if (*a == '%') {
int x, y;
a++;
}
- t = realloc(r, n + 2);
- if (!t) {
- free(r);
+ if (!GREEDY_REALLOC(r, allocated, n + 2))
return -ENOMEM;
- }
- r = t;
r[n++] = c;
}
char *path = NULL;
unsigned n_argv = 0, j;
char **argv = NULL;
+ size_t allocated = 0;
int r;
assert(b);
(*p) ++;
if (ul >= n_argv) {
- char **x;
-
- x = realloc(argv, sizeof(char*) * (ul + 2));
- if (!x) {
+ if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) {
r = -ENOMEM;
goto fail;
}
- memset(x + n_argv, 0, sizeof(char*) * (ul - n_argv + 2));
-
- argv = x;
n_argv = ul + 1;
}
return 0;
}
-static int parse_container_address(sd_bus *b, const char **p, char **guid) {
+static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) {
_cleanup_free_ char *machine = NULL;
int r;
if (!machine)
return -EINVAL;
+ if (!filename_is_safe(machine))
+ return -EINVAL;
+
free(b->machine);
b->machine = machine;
machine = NULL;
return 0;
}
+static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) {
+ _cleanup_free_ char *machine = NULL;
+ int r;
+
+ assert(b);
+ assert(p);
+ assert(*p);
+ assert(guid);
+
+ while (**p != 0 && **p != ';') {
+ r = parse_address_key(p, "guid", guid);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
+ r = parse_address_key(p, "machine", &machine);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
+ skip_address_key(p);
+ }
+
+ if (!machine)
+ return -EINVAL;
+
+ if (!filename_is_safe(machine))
+ return -EINVAL;
+
+ free(b->machine);
+ b->machine = machine;
+ machine = NULL;
+
+ free(b->kernel);
+ b->kernel = strdup("/dev/kdbus/0-system/bus");
+ if (!b->kernel)
+ return -ENOMEM;
+
+ return 0;
+}
+
static void bus_reset_parsed_address(sd_bus *b) {
assert(b);
return r;
break;
- } else if (startswith(a, "x-container:")) {
+ } else if (startswith(a, "x-container-unix:")) {
- a += 12;
- r = parse_container_address(b, &a, &guid);
+ a += 17;
+ r = parse_container_unix_address(b, &a, &guid);
+ if (r < 0)
+ return r;
+
+ break;
+ } else if (startswith(a, "x-container-kernel:")) {
+
+ a += 19;
+ r = parse_container_kernel_address(b, &a, &guid);
if (r < 0)
return r;
assert(b);
for (;;) {
- sd_bus_close(b);
+ bool skipped = false;
- if (b->exec_path) {
+ bus_close_fds(b);
+ if (b->exec_path)
r = bus_socket_exec(b);
- if (r >= 0)
- return r;
-
- b->last_connect_error = -r;
- } else if (b->kernel) {
-
+ else if (b->machine && b->kernel)
+ r = bus_container_connect_kernel(b);
+ else if (b->machine && b->sockaddr.sa.sa_family != AF_UNSPEC)
+ r = bus_container_connect_socket(b);
+ else if (b->kernel)
r = bus_kernel_connect(b);
- if (r >= 0)
- return r;
-
- b->last_connect_error = -r;
-
- } else if (b->machine) {
-
- r = bus_container_connect(b);
- if (r >= 0)
- return r;
-
- b->last_connect_error = -r;
-
- } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
-
+ else if (b->sockaddr.sa.sa_family != AF_UNSPEC)
r = bus_socket_connect(b);
- if (r >= 0)
- return r;
+ else
+ skipped = true;
+
+ if (!skipped) {
+ if (r >= 0) {
+ r = attach_io_events(b);
+ if (r >= 0)
+ return r;
+ }
b->last_connect_error = -r;
}
return r;
e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
- if (e) {
+ if (e)
r = sd_bus_set_address(b, e);
- if (r < 0)
- goto fail;
- } else {
- b->sockaddr.un.sun_family = AF_UNIX;
- strncpy(b->sockaddr.un.sun_path, "/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
- b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/dbus/system_bus_socket") - 1;
- }
+ else
+#ifdef ENABLE_KDBUS
+ r = sd_bus_set_address(b, "kernel:path=/dev/kdbus/0-system/bus;unix:path=/run/dbus/system_bus_socket");
+#else
+ r = sd_bus_set_address(b, "unix:path=/run/dbus/system_bus_socket");
+#endif
+
+ if (r < 0)
+ goto fail;
b->bus_client = true;
+ /* Let's do per-method access control on the system bus. We
+ * need the caller's UID and capability set for that. */
+ b->trusted = false;
+ b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
+
r = sd_bus_start(b);
if (r < 0)
goto fail;
_public_ int sd_bus_open_user(sd_bus **ret) {
const char *e;
sd_bus *b;
- size_t l;
int r;
assert_return(ret, -EINVAL);
goto fail;
} else {
e = secure_getenv("XDG_RUNTIME_DIR");
- if (!e) {
- r = -ENOENT;
- goto fail;
+ if (e) {
+ _cleanup_free_ char *ee = NULL;
+
+ ee = bus_address_escape(e);
+ if (!ee) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+#ifdef ENABLE_KDBUS
+ asprintf(&b->address, "kernel:path=/dev/kdbus/%lu-user/bus;unix:path=%s/bus", (unsigned long) getuid(), ee);
+#else
+ b->address = strjoin("unix:path=", ee, "/bus", NULL);
+#endif
+ } else {
+#ifdef ENABLE_KDBUS
+ asprintf(&b->address, "kernel:path=/dev/kdbus/%lu-user/bus", (unsigned long) getuid());
+#else
+ return -ECONNREFUSED;
+#endif
}
- l = strlen(e);
- if (l + 4 > sizeof(b->sockaddr.un.sun_path)) {
- r = -E2BIG;
+ if (!b->address) {
+ r = -ENOMEM;
goto fail;
}
-
- b->sockaddr.un.sun_family = AF_UNIX;
- memcpy(mempcpy(b->sockaddr.un.sun_path, e, l), "/bus", 4);
- b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + l + 4;
}
b->bus_client = true;
+ /* We don't do any per-method access control on the user
+ * bus. */
+ b->trusted = true;
+
r = sd_bus_start(b);
if (r < 0)
goto fail;
assert_return(machine, -EINVAL);
assert_return(ret, -EINVAL);
+ assert_return(filename_is_safe(machine), -EINVAL);
e = bus_address_escape(machine);
if (!e)
return -ENOMEM;
- p = strjoin("x-container:machine=", e, NULL);
+#ifdef ENABLE_KDBUS
+ p = strjoin("x-container-kernel:machine=", e, ";x-container-unix:machine=", e, NULL);
+#else
+ p = strjoin("x-container-unix:machine=", e, NULL);
+#endif
if (!p)
return -ENOMEM;
/* We'll leave the fd open in case this is a kernel bus, since
* there might still be memblocks around that reference this
- * bus, and they might need to invoke the
- * KDBUS_CMD_MSG_RELEASE ioctl on the fd when they are
- * freed. */
+ * bus, and they might need to invoke the * KDBUS_CMD_FREE
+ * ioctl on the fd when they are freed. */
}
static void bus_enter_closing(sd_bus *bus) {
}
_public_ sd_bus *sd_bus_unref(sd_bus *bus) {
- assert_return(bus, NULL);
+
+ if (!bus)
+ return NULL;
if (REFCNT_DEC(bus->n_ref) <= 0)
bus_free(bus);
return 0;
}
-static int bus_seal_message(sd_bus *b, sd_bus_message *m) {
+static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
assert(b);
assert(m);
- if (m->header->version > b->message_version)
- return -EPERM;
-
if (m->sealed) {
/* If we copy the same message to multiple
- * destinations, avoid using the same serial
+ * destinations, avoid using the same cookie
* numbers. */
- b->serial = MAX(b->serial, BUS_MESSAGE_SERIAL(m));
+ b->cookie = MAX(b->cookie, BUS_MESSAGE_COOKIE(m));
return 0;
}
- return bus_message_seal(m, ++b->serial);
+ if (timeout == 0)
+ timeout = BUS_DEFAULT_TIMEOUT;
+
+ return bus_message_seal(m, ++b->cookie, timeout);
+}
+
+static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
+ assert(b);
+
+ /* Do packet version and endianess already match? */
+ if ((b->message_version == 0 || b->message_version == (*m)->header->version) &&
+ (b->message_endian == 0 || b->message_endian == (*m)->header->endian))
+ return 0;
+
+ /* No? Then remarshal! */
+ return bus_message_remarshal(b, m);
}
int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
assert(b);
assert(m);
- if (m->header->version > b->message_version)
- return -EPERM;
-
/* The bus specification says the serial number cannot be 0,
* hence let's fill something in for synthetic messages. Since
* synthetic messages might have a fake sender and we don't
* than (uint64_t) -1 since dbus1 only had 32bit identifiers,
* even though kdbus can do 64bit. */
- return bus_message_seal(m, 0xFFFFFFFFULL);
+ return bus_message_seal(m, 0xFFFFFFFFULL, 0);
}
-static int bus_write_message(sd_bus *bus, sd_bus_message *message, size_t *idx) {
+static int bus_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
int r;
assert(bus);
- assert(message);
+ assert(m);
if (bus->is_kernel)
- return bus_kernel_write_message(bus, message);
+ r = bus_kernel_write_message(bus, m);
else
- return bus_socket_write_message(bus, message, idx);
+ r = bus_socket_write_message(bus, m, idx);
+
+ if (r <= 0)
+ return r;
+
+ if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(m))
+ log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s",
+ bus_message_type_to_string(m->header->type),
+ strna(sd_bus_message_get_sender(m)),
+ strna(sd_bus_message_get_destination(m)),
+ strna(sd_bus_message_get_path(m)),
+ strna(sd_bus_message_get_interface(m)),
+ strna(sd_bus_message_get_member(m)),
+ (unsigned long) BUS_MESSAGE_COOKIE(m),
+ (unsigned long) m->reply_cookie,
+ strna(m->error.message));
return r;
}
}
int bus_rqueue_make_room(sd_bus *bus) {
- sd_bus_message **q;
- unsigned x;
-
- x = bus->rqueue_size + 1;
-
- if (bus->rqueue_allocated >= x)
- return 0;
+ assert(bus);
- if (x > BUS_RQUEUE_MAX)
+ if (bus->rqueue_size >= BUS_RQUEUE_MAX)
return -ENOBUFS;
- q = realloc(bus->rqueue, x * sizeof(sd_bus_message*));
- if (!q)
+ if (!GREEDY_REALLOC(bus->rqueue, bus->rqueue_allocated, bus->rqueue_size + 1))
return -ENOMEM;
- bus->rqueue = q;
- bus->rqueue_allocated = x;
-
return 0;
}
}
}
-_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
+_public_ int sd_bus_send(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
int r;
assert_return(bus, -EINVAL);
return -ENOTSUP;
}
- /* If the serial number isn't kept, then we know that no reply
+ /* If the cookie number isn't kept, then we know that no reply
* is expected */
- if (!serial && !m->sealed)
- m->header->flags |= SD_BUS_MESSAGE_NO_REPLY_EXPECTED;
+ if (!cookie && !m->sealed)
+ m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
- r = bus_seal_message(bus, m);
+ r = bus_seal_message(bus, m, 0);
+ if (r < 0)
+ return r;
+
+ /* Remarshall if we have to. This will possible unref the
+ * message and place a replacement in m */
+ r = bus_remarshal_message(bus, &m);
if (r < 0)
return r;
/* If this is a reply and no reply was requested, then let's
* suppress this, if we can */
- if (m->dont_send && !serial)
+ if (m->dont_send && !cookie)
return 1;
if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
size_t idx = 0;
r = bus_write_message(bus, m, &idx);
- if (r < 0)
+ if (r < 0) {
+ if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+ bus_enter_closing(bus);
+
return r;
- else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) {
+ } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) {
/* Wasn't fully written. So let's remember how
* much was written. Note that the first entry
* of the wqueue array is always allocated so
bus->windex = idx;
}
} else {
- sd_bus_message **q;
-
/* Just append it to the queue. */
if (bus->wqueue_size >= BUS_WQUEUE_MAX)
return -ENOBUFS;
- q = realloc(bus->wqueue, sizeof(sd_bus_message*) * (bus->wqueue_size + 1));
- if (!q)
+ if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
return -ENOMEM;
- bus->wqueue = q;
- q[bus->wqueue_size ++] = sd_bus_message_ref(m);
+ bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m);
}
- if (serial)
- *serial = BUS_MESSAGE_SERIAL(m);
+ if (cookie)
+ *cookie = BUS_MESSAGE_COOKIE(m);
return 1;
}
-_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *serial) {
+_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
int r;
assert_return(bus, -EINVAL);
return r;
}
- return sd_bus_send(bus, m, serial);
+ return sd_bus_send(bus, m, cookie);
}
static usec_t calc_elapse(uint64_t usec) {
if (usec == (uint64_t) -1)
return 0;
- if (usec == 0)
- usec = BUS_DEFAULT_TIMEOUT;
-
return now(CLOCK_MONOTONIC) + usec;
}
_public_ int sd_bus_call_async(
sd_bus *bus,
- sd_bus_message *m,
+ sd_bus_message *_m,
sd_bus_message_handler_t callback,
void *userdata,
uint64_t usec,
- uint64_t *serial) {
+ uint64_t *cookie) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
struct reply_callback *c;
int r;
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(m, -EINVAL);
assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
- assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
+ assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
if (r < 0)
return r;
- if (usec != (uint64_t) -1) {
- r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare);
- if (r < 0)
- return r;
- }
+ r = prioq_ensure_allocated(&bus->reply_callbacks_prioq, timeout_compare);
+ if (r < 0)
+ return r;
- r = bus_seal_message(bus, m);
+ r = bus_seal_message(bus, m, usec);
+ if (r < 0)
+ return r;
+
+ r = bus_remarshal_message(bus, &m);
if (r < 0)
return r;
c->callback = callback;
c->userdata = userdata;
- c->serial = BUS_MESSAGE_SERIAL(m);
- c->timeout = calc_elapse(usec);
+ c->cookie = BUS_MESSAGE_COOKIE(m);
+ c->timeout = calc_elapse(m->timeout);
- r = hashmap_put(bus->reply_callbacks, &c->serial, c);
+ r = hashmap_put(bus->reply_callbacks, &c->cookie, c);
if (r < 0) {
free(c);
return r;
r = prioq_put(bus->reply_callbacks_prioq, c, &c->prioq_idx);
if (r < 0) {
c->timeout = 0;
- sd_bus_call_async_cancel(bus, c->serial);
+ sd_bus_call_async_cancel(bus, c->cookie);
return r;
}
}
- r = sd_bus_send(bus, m, serial);
+ r = sd_bus_send(bus, m, cookie);
if (r < 0) {
- sd_bus_call_async_cancel(bus, c->serial);
+ sd_bus_call_async_cancel(bus, c->cookie);
return r;
}
return r;
}
-_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t serial) {
+_public_ int sd_bus_call_async_cancel(sd_bus *bus, uint64_t cookie) {
struct reply_callback *c;
assert_return(bus, -EINVAL);
- assert_return(serial != 0, -EINVAL);
+ assert_return(cookie != 0, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- c = hashmap_remove(bus->reply_callbacks, &serial);
+ c = hashmap_remove(bus->reply_callbacks, &cookie);
if (!c)
return 0;
_public_ int sd_bus_call(
sd_bus *bus,
- sd_bus_message *m,
+ sd_bus_message *_m,
uint64_t usec,
sd_bus_error *error,
sd_bus_message **reply) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
usec_t timeout;
- uint64_t serial;
+ uint64_t cookie;
unsigned i;
int r;
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(m, -EINVAL);
assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
- assert_return(!(m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
+ assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
assert_return(!bus_error_is_dirty(error), -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
i = bus->rqueue_size;
- r = sd_bus_send(bus, m, &serial);
+ r = bus_seal_message(bus, m, usec);
+ if (r < 0)
+ return r;
+
+ r = bus_remarshal_message(bus, &m);
if (r < 0)
return r;
- timeout = calc_elapse(usec);
+ r = sd_bus_send(bus, m, &cookie);
+ if (r < 0)
+ return r;
+
+ timeout = calc_elapse(m->timeout);
for (;;) {
usec_t left;
incoming = bus->rqueue[i];
- if (incoming->reply_serial == serial) {
+ if (incoming->reply_cookie == cookie) {
/* Found a match! */
memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
sd_bus_message_unref(incoming);
return r;
- } else if (incoming->header->serial == serial &&
+ } else if (BUS_MESSAGE_COOKIE(incoming) == cookie &&
bus->unique_name &&
incoming->sender &&
streq(bus->unique_name, incoming->sender)) {
}
r = bus_read_message(bus);
- if (r < 0)
+ if (r < 0) {
+ if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+ bus_enter_closing(bus);
+
return r;
+ }
if (r > 0)
continue;
r = bus_poll(bus, true, left);
if (r < 0)
return r;
+ if (r == 0)
+ return -ETIMEDOUT;
r = dispatch_wqueue(bus);
- if (r < 0)
+ if (r < 0) {
+ if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+ bus_enter_closing(bus);
+
return r;
+ }
}
}
r = bus_message_new_synthetic_error(
bus,
- c->serial,
+ c->cookie,
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out"),
&m);
if (r < 0)
return r;
assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
- hashmap_remove(bus->reply_callbacks, &c->serial);
+ hashmap_remove(bus->reply_callbacks, &c->cookie);
bus->current = m;
bus->iteration_counter ++;
m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
return -EIO;
- if (m->reply_serial != bus->hello_serial)
+ if (m->reply_cookie != bus->hello_cookie)
return -EIO;
return 0;
m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
return 0;
- c = hashmap_remove(bus->reply_callbacks, &m->reply_serial);
+ c = hashmap_remove(bus->reply_callbacks, &m->reply_cookie);
if (!c)
return 0;
if (!streq_ptr(m->interface, "org.freedesktop.DBus.Peer"))
return 0;
- if (m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
+ if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
return 1;
if (streq_ptr(m->member, "Ping"))
bus->current = m;
bus->iteration_counter++;
- log_debug("Got message sender=%s object=%s interface=%s member=%s",
+ log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%lu reply_cookie=%lu error=%s",
+ bus_message_type_to_string(m->header->type),
strna(sd_bus_message_get_sender(m)),
+ strna(sd_bus_message_get_destination(m)),
strna(sd_bus_message_get_path(m)),
strna(sd_bus_message_get_interface(m)),
- strna(sd_bus_message_get_member(m)));
+ strna(sd_bus_message_get_member(m)),
+ (unsigned long) BUS_MESSAGE_COOKIE(m),
+ (unsigned long) m->reply_cookie,
+ strna(m->error.message));
r = process_hello(bus, m);
if (r != 0)
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL) {
+ log_debug("Unprocessed message call sender=%s object=%s interface=%s member=%s",
+ strna(sd_bus_message_get_sender(m)),
+ strna(sd_bus_message_get_path(m)),
+ strna(sd_bus_message_get_interface(m)),
+ strna(sd_bus_message_get_member(m)));
+
r = sd_bus_reply_method_errorf(
m,
SD_BUS_ERROR_UNKNOWN_OBJECT,
/* First, fail all outstanding method calls */
r = bus_message_new_synthetic_error(
bus,
- c->serial,
+ c->cookie,
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
&m);
if (r < 0)
if (c->timeout != 0)
prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
- hashmap_remove(bus->reply_callbacks, &c->serial);
+ hashmap_remove(bus->reply_callbacks, &c->cookie);
bus->current = m;
bus->iteration_counter++;
switch (bus->state) {
case BUS_UNSET:
- case BUS_CLOSED:
return -ENOTCONN;
+ case BUS_CLOSED:
+ return -ECONNRESET;
+
case BUS_OPENING:
r = bus_socket_process_opening(bus);
- if (r == -ECONNRESET || r == -EPIPE) {
+ if (r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
bus_enter_closing(bus);
r = 1;
} else if (r < 0)
case BUS_AUTHENTICATING:
r = bus_socket_process_authenticating(bus);
- if (r == -ECONNRESET || r == -EPIPE) {
+ if (r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
bus_enter_closing(bus);
r = 1;
} else if (r < 0)
case BUS_RUNNING:
case BUS_HELLO:
r = process_running(bus, ret);
- if (r == -ECONNRESET || r == -EPIPE) {
+ if (r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
bus_enter_closing(bus);
r = 1;
for (;;) {
r = dispatch_wqueue(bus);
- if (r < 0)
+ if (r < 0) {
+ if (r == -EPIPE || r == -ENOTCONN || r == -ESHUTDOWN)
+ bus_enter_closing(bus);
+
return r;
+ }
if (bus->wqueue_size <= 0)
return 0;
return 1;
}
+static int attach_io_events(sd_bus *bus) {
+ int r;
+
+ assert(bus);
+
+ if (bus->input_fd < 0)
+ return 0;
+
+ if (!bus->event)
+ return 0;
+
+ if (!bus->input_io_event_source) {
+ r = sd_event_add_io(bus->event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(bus->input_io_event_source, bus->event_priority);
+ } else
+ r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd);
+
+ if (r < 0)
+ return r;
+
+ if (bus->output_fd != bus->input_fd) {
+ assert(bus->output_fd >= 0);
+
+ if (!bus->output_io_event_source) {
+ r = sd_event_add_io(bus->event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(bus->output_io_event_source, bus->event_priority);
+ } else
+ r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd);
+
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static void detach_io_events(sd_bus *bus) {
+ assert(bus);
+
+ if (bus->input_io_event_source) {
+ sd_event_source_set_enabled(bus->input_io_event_source, SD_EVENT_OFF);
+ bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
+ }
+
+ if (bus->output_io_event_source) {
+ sd_event_source_set_enabled(bus->output_io_event_source, SD_EVENT_OFF);
+ bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
+ }
+}
+
_public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
int r;
return r;
}
- r = sd_event_add_io(bus->event, bus->input_fd, 0, io_callback, bus, &bus->input_io_event_source);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(bus->input_io_event_source, priority);
- if (r < 0)
- goto fail;
-
- if (bus->output_fd != bus->input_fd) {
- r = sd_event_add_io(bus->event, bus->output_fd, 0, io_callback, bus, &bus->output_io_event_source);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(bus->output_io_event_source, priority);
- if (r < 0)
- goto fail;
- }
+ bus->event_priority = priority;
- r = sd_event_source_set_prepare(bus->input_io_event_source, prepare_callback);
+ r = sd_event_add_monotonic(bus->event, 0, 0, time_callback, bus, &bus->time_event_source);
if (r < 0)
goto fail;
- r = sd_event_add_monotonic(bus->event, 0, 0, time_callback, bus, &bus->time_event_source);
+ r = sd_event_source_set_priority(bus->time_event_source, priority);
if (r < 0)
goto fail;
- r = sd_event_source_set_priority(bus->time_event_source, priority);
+ r = sd_event_add_exit(bus->event, quit_callback, bus, &bus->quit_event_source);
if (r < 0)
goto fail;
- r = sd_event_add_quit(bus->event, quit_callback, bus, &bus->quit_event_source);
+ r = attach_io_events(bus);
if (r < 0)
goto fail;
_public_ int sd_bus_detach_event(sd_bus *bus) {
assert_return(bus, -EINVAL);
- assert_return(bus->event, -ENXIO);
- if (bus->input_io_event_source) {
- sd_event_source_set_enabled(bus->input_io_event_source, SD_EVENT_OFF);
- bus->input_io_event_source = sd_event_source_unref(bus->input_io_event_source);
- }
+ if (!bus->event)
+ return 0;
- if (bus->output_io_event_source) {
- sd_event_source_set_enabled(bus->output_io_event_source, SD_EVENT_OFF);
- bus->output_io_event_source = sd_event_source_unref(bus->output_io_event_source);
- }
+ detach_io_events(bus);
if (bus->time_event_source) {
sd_event_source_set_enabled(bus->time_event_source, SD_EVENT_OFF);
if (bus->event)
bus->event = sd_event_unref(bus->event);
- return 0;
+ return 1;
}
_public_ sd_event* sd_bus_get_event(sd_bus *bus) {
}
_public_ int sd_bus_default_system(sd_bus **ret) {
- static __thread sd_bus *default_system_bus = NULL;
+ 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 sd_bus *default_user_bus = NULL;
+ static thread_local sd_bus *default_user_bus = NULL;
return bus_default(sd_bus_open_user, &default_user_bus, ret);
}
int r;
assert_return(bus, -EINVAL);
- assert_return(mask <= _SD_BUS_CREDS_MAX, -ENOTSUP);
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
assert_return(ret, -EINVAL);
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(!bus_pid_changed(bus), -ECHILD);
c->uid = bus->ucred.uid;
c->gid = bus->ucred.gid;
- c->mask |= ((SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask) & bus->creds_mask;
+ c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
}
if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
return -ENOMEM;
}
- c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT | bus->creds_mask;
+ c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
r = bus_creds_add_more(c, mask, pid, 0);
*ret = c;
return 0;
}
+
+_public_ int sd_bus_try_close(sd_bus *bus) {
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+ assert_return(bus->is_kernel, -ENOTSUP);
+
+ if (bus->rqueue_size > 0)
+ return -EBUSY;
+
+ if (bus->wqueue_size > 0)
+ return -EBUSY;
+
+ r = bus_kernel_try_close(bus);
+ if (r < 0)
+ return r;
+
+ sd_bus_close(bus);
+ return 0;
+}