#include "bus-message.h"
#include "bus-type.h"
#include "bus-socket.h"
+#include "bus-kernel.h"
#include "bus-control.h"
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
free(b->unique_name);
free(b->auth_buffer);
free(b->address);
+ free(b->kernel);
free(b->exec_path);
strv_free(b->exec_argv);
assert(bus);
- if (!bus->bus_client)
+ if (!bus->bus_client || bus->is_kernel)
return 0;
r = sd_bus_message_new_method_call(
int bus_start_running(sd_bus *bus) {
assert(bus);
- if (bus->bus_client) {
+ if (bus->bus_client && !bus->is_kernel) {
bus->state = BUS_HELLO;
return 1;
}
static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
_cleanup_free_ char *host = NULL, *port = NULL, *family = NULL;
- struct addrinfo hints, *result;
int r;
+ struct addrinfo *result, hints = {
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_ADDRCONFIG,
+ };
assert(b);
assert(p);
if (!host || !port)
return -EINVAL;
- zero(hints);
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_ADDRCONFIG;
-
if (family) {
if (streq(family, "ipv4"))
hints.ai_family = AF_INET;
return r;
}
+static int parse_kernel_address(sd_bus *b, const char **p, char **guid) {
+ _cleanup_free_ char *path = 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, "path", &path);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
+ skip_address_key(p);
+ }
+
+ if (!path)
+ return -EINVAL;
+
+ free(b->kernel);
+ b->kernel = path;
+ path = NULL;
+
+ return 0;
+}
+
static void bus_reset_parsed_address(sd_bus *b) {
assert(b);
b->exec_path = NULL;
b->exec_argv = NULL;
b->server_id = SD_ID128_NULL;
+ free(b->kernel);
+ b->kernel = NULL;
}
static int bus_parse_next_address(sd_bus *b) {
break;
+ } else if (startswith(a, "kernel:")) {
+
+ a += 7;
+ r = parse_kernel_address(b, &a, &guid);
+ if (r < 0)
+ return r;
+
+ break;
}
a = strchr(a, ';');
if (r >= 0)
return r;
+ b->last_connect_error = -r;
+ } else if (b->kernel) {
+
+ r = bus_kernel_connect(b);
+ if (r >= 0)
+ return r;
+
b->last_connect_error = -r;
}
}
static int bus_start_fd(sd_bus *b) {
+ struct stat st;
int r;
assert(b);
return r;
}
- return bus_socket_take_fd(b);
+ if (fstat(b->input_fd, &st) < 0)
+ return -errno;
+
+ if (S_ISCHR(b->input_fd))
+ return bus_kernel_take_fd(b);
+ else
+ return bus_socket_take_fd(b);
}
int sd_bus_start(sd_bus *bus) {
if (bus->input_fd >= 0)
r = bus_start_fd(bus);
- else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path)
+ else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel)
r = bus_start_address(bus);
else
return -EINVAL;
while (bus->wqueue_size > 0) {
- r = bus_socket_write_message(bus, bus->wqueue[0], &bus->windex);
+ if (bus->is_kernel)
+ r = bus_kernel_write_message(bus, bus->wqueue[0]);
+ else
+ r = bus_socket_write_message(bus, bus->wqueue[0], &bus->windex);
+
if (r < 0) {
sd_bus_close(bus);
return r;
} else if (r == 0)
/* Didn't do anything this time */
return ret;
- else if (bus->windex >= bus->wqueue[0]->size) {
+ else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
/* Fully written. Let's drop the entry from
* the queue.
*
/* Try to read a new message */
do {
- r = bus_socket_read_message(bus, &z);
+ if (bus->is_kernel)
+ r = bus_kernel_read_message(bus, &z);
+ else
+ r = bus_socket_read_message(bus, &z);
+
if (r < 0) {
sd_bus_close(bus);
return r;
if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
size_t idx = 0;
- r = bus_socket_write_message(bus, m, &idx);
+ if (bus->is_kernel)
+ r = bus_kernel_write_message(bus, m);
+ else
+ r = bus_socket_write_message(bus, m, &idx);
+
if (r < 0) {
sd_bus_close(bus);
return r;
- } else if (idx < m->size) {
+ } 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
if (r < 0)
return r;
- c = new(struct reply_callback, 1);
+ c = new0(struct reply_callback, 1);
if (!c)
return -ENOMEM;
room = true;
}
- r = bus_socket_read_message(bus, &incoming);
+ if (bus->is_kernel)
+ r = bus_kernel_read_message(bus, &incoming);
+ else
+ r = bus_socket_read_message(bus, &incoming);
if (r < 0)
return r;
if (incoming) {
/* Found a match! */
if (incoming->header->type == SD_BUS_MESSAGE_TYPE_METHOD_RETURN) {
- *reply = incoming;
+
+ if (reply)
+ *reply = incoming;
+ else
+ sd_bus_message_unref(incoming);
+
return 0;
}
r = sd_bus_message_append(reply, "s", sd_id128_to_string(id, sid));
} else {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_INIT;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_error_set(&error,
"org.freedesktop.DBus.Error.UnknownMethod",
}
static int process_object(sd_bus *bus, sd_bus_message *m) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_INIT;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
struct object_callback *c;
int r;
if (m->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_INIT;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_error_set(&error, "org.freedesktop.DBus.Error.UnknownObject", "Unknown object '%s'.", m->path);
}
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
- struct pollfd p[2];
+ struct pollfd p[2] = {};
int r, e, n;
struct timespec ts;
usec_t until, m;
if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
m = timeout_usec;
- zero(p);
p[0].fd = bus->input_fd;
-
if (bus->output_fd == bus->input_fd) {
p[0].events = e;
n = 1;
if (!callback)
return -EINVAL;
- f = new(struct filter_callback, 1);
+ f = new0(struct filter_callback, 1);
if (!f)
return -ENOMEM;
f->callback = callback;
if (r < 0)
return r;
- c = new(struct object_callback, 1);
+ c = new0(struct object_callback, 1);
if (!c)
return -ENOMEM;
return r;
return q;
}
+
+int sd_bus_emit_signal(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *types, ...) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ va_list ap;
+ int r;
+
+ if (!bus)
+ return -EINVAL;
+
+ r = sd_bus_message_new_signal(bus, path, interface, member, &m);
+ if (r < 0)
+ return r;
+
+ va_start(ap, types);
+ r = bus_message_append_ap(m, types, ap);
+ va_end(ap);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(bus, m, NULL);
+}
+
+int sd_bus_call_method(
+ sd_bus *bus,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ sd_bus_error *error,
+ sd_bus_message **reply,
+ const char *types, ...) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ va_list ap;
+ int r;
+
+ if (!bus)
+ return -EINVAL;
+
+ r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
+ if (r < 0)
+ return r;
+
+ va_start(ap, types);
+ r = bus_message_append_ap(m, types, ap);
+ va_end(ap);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
+}
+
+int sd_bus_reply_method_return(
+ sd_bus *bus,
+ sd_bus_message *call,
+ const char *types, ...) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ va_list ap;
+ int r;
+
+ if (!bus)
+ return -EINVAL;
+ if (!call)
+ return -EINVAL;
+ if (!call->sealed)
+ return -EPERM;
+ if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+ return -EINVAL;
+
+ if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
+ return 0;
+
+ r = sd_bus_message_new_method_return(bus, call, &m);
+ if (r < 0)
+ return r;
+
+ va_start(ap, types);
+ r = bus_message_append_ap(m, types, ap);
+ va_end(ap);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(bus, m, NULL);
+}
+
+int sd_bus_reply_method_error(
+ sd_bus *bus,
+ sd_bus_message *call,
+ const sd_bus_error *e) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ int r;
+
+ if (!bus)
+ return -EINVAL;
+ if (!call)
+ return -EINVAL;
+ if (!call->sealed)
+ return -EPERM;
+ if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL)
+ return -EINVAL;
+ if (!sd_bus_error_is_set(e))
+ return -EINVAL;
+
+ if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
+ return 0;
+
+ r = sd_bus_message_new_method_error(bus, call, e, &m);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(bus, m, NULL);
+}