forked from ports/contrib
2712 lines
81 KiB
Diff
2712 lines
81 KiB
Diff
From 8930d787dfc20e1514d6f03e41690df0e9a507da Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 26 Oct 2018 15:25:36 +0200
|
|
Subject: [PATCH 01/17] Add subd headers and sources
|
|
|
|
These provide a small set of wrapper functions around the low-level
|
|
libdbus API that act like a shim for sd-bus.
|
|
---
|
|
dbus/subd-sdbus.c | 403 +++++++++++++++++++++++++++++++++++++++++++
|
|
dbus/subd-vtable.c | 337 ++++++++++++++++++++++++++++++++++++
|
|
dbus/subd-watch.c | 180 +++++++++++++++++++
|
|
include/subd-sdbus.h | 142 +++++++++++++++
|
|
include/subd.h | 41 +++++
|
|
5 files changed, 1103 insertions(+)
|
|
create mode 100644 dbus/subd-sdbus.c
|
|
create mode 100644 dbus/subd-vtable.c
|
|
create mode 100644 dbus/subd-watch.c
|
|
create mode 100644 include/subd-sdbus.h
|
|
create mode 100644 include/subd.h
|
|
|
|
diff --git a/dbus/subd-sdbus.c b/dbus/subd-sdbus.c
|
|
new file mode 100644
|
|
index 0000000..eccdc14
|
|
--- /dev/null
|
|
+++ b/dbus/subd-sdbus.c
|
|
@@ -0,0 +1,403 @@
|
|
+#include <errno.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include "subd.h"
|
|
+
|
|
+int sd_bus_open_user(sd_bus **bus) {
|
|
+ if (!dbus_threads_init_default()) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ *bus = dbus_bus_get(DBUS_BUS_SESSION, NULL);
|
|
+ if (*bus == NULL) {
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
|
|
+ if (dbus_bus_request_name(bus, name, flags, NULL) == -1) {
|
|
+ return -EEXIST;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void sd_bus_slot_unref(int *slot) {
|
|
+ // not used
|
|
+}
|
|
+
|
|
+void sd_bus_flush_close_unref(sd_bus *bus) {
|
|
+ // only flush and unref, no need to dbus_connection_close shared connections
|
|
+ dbus_connection_flush(bus);
|
|
+ dbus_connection_unref(bus);
|
|
+}
|
|
+
|
|
+void sd_bus_error_set_const(sd_bus_error *err, const char *name, const char *msg) {
|
|
+ dbus_set_error_const(err, name, msg);
|
|
+}
|
|
+
|
|
+int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newmsg) {
|
|
+ sd_bus_message *new_message = NULL;
|
|
+ DBusMessage *message = NULL;
|
|
+ // Allocate a new "method return" DBusMessage
|
|
+ if ((message = dbus_message_new_method_return(msg->message)) == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ // Allocate a new sd_bus_message
|
|
+ new_message = malloc(sizeof(sd_bus_message));
|
|
+ if (new_message == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ // Populate the fields of the new sd_bus_message so that it knows which bus
|
|
+ // it is to be sent on, and what DBusMessage it contains.
|
|
+ new_message->bus = msg->bus;
|
|
+ new_message->message = message;
|
|
+ new_message->ref_count = 1;
|
|
+
|
|
+ //Also initialize the sd_bus_message's iterator stack, ...
|
|
+ new_message->iters = malloc(sizeof(struct wl_list));
|
|
+ if (new_message->iters == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+ wl_list_init(new_message->iters);
|
|
+
|
|
+ // ... and push a new append iterator to it.
|
|
+ struct msg_iter *iter = malloc(sizeof(struct msg_iter));
|
|
+ if (iter == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+ dbus_message_iter_init_append(new_message->message, &iter->iter);
|
|
+ wl_list_insert(new_message->iters, &iter->link);
|
|
+ new_message->iter = &iter->iter;
|
|
+
|
|
+ *newmsg = new_message;
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ //XXX list_destroy(new_message->iters);
|
|
+ free(new_message);
|
|
+ dbus_message_unref(message);
|
|
+ *newmsg = NULL;
|
|
+ return -ENOMEM;
|
|
+}
|
|
+
|
|
+int sd_bus_message_open_container(sd_bus_message *msg, char type,
|
|
+ const char *signature) {
|
|
+ struct msg_iter *sub = malloc(sizeof(struct msg_iter));
|
|
+ if (sub == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (!dbus_message_iter_open_container(msg->iter, type, signature, &sub->iter)) {
|
|
+ goto error;
|
|
+ }
|
|
+ wl_list_insert(msg->iters, &sub->link);
|
|
+ msg->iter = &sub->iter;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ free(sub);
|
|
+ return -ENOMEM;
|
|
+}
|
|
+
|
|
+int sd_bus_message_close_container(sd_bus_message *msg) {
|
|
+ // Remove the iterator we want to close from from the iterator stack
|
|
+ struct msg_iter *iter = wl_container_of(msg->iters->next, iter, link);
|
|
+ wl_list_remove(&iter->link);
|
|
+
|
|
+ // Set msg's current iterator to the top of the iterator stack.
|
|
+ struct msg_iter *new_head = wl_container_of(msg->iters->next, iter, link);
|
|
+ msg->iter = &new_head->iter;
|
|
+
|
|
+ // Close the container.
|
|
+ if (!dbus_message_iter_close_container(msg->iter, &iter->iter)) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int sd_bus_message_append(sd_bus_message *msg, const char *signature, ...) {
|
|
+ if (!dbus_signature_validate(signature, NULL)) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ va_list ap;
|
|
+ DBusSignatureIter iter;
|
|
+ va_start(ap, signature);
|
|
+ dbus_signature_iter_init(&iter, signature);
|
|
+
|
|
+ do {
|
|
+ int type = dbus_signature_iter_get_current_type(&iter);
|
|
+ if (!dbus_type_is_basic(type)) {
|
|
+ va_end(ap);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ DBusBasicValue val = va_arg(ap, DBusBasicValue);
|
|
+ if (!dbus_message_iter_append_basic(msg->iter, type, &val)) {
|
|
+ va_end(ap);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ } while(dbus_signature_iter_next(&iter));
|
|
+
|
|
+ va_end(ap);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void sd_bus_message_unref(sd_bus_message *msg) {
|
|
+ dbus_message_unref(msg->message);
|
|
+ if (msg->ref_count == 0) {
|
|
+ //XXX list_destroy(msg->iters);
|
|
+ free(msg);
|
|
+ }
|
|
+}
|
|
+
|
|
+int sd_bus_message_peek_type(sd_bus_message *msg, void *unused,
|
|
+ const char **signature) {
|
|
+ char *s = dbus_message_iter_get_signature(msg->iter);
|
|
+ if (s == NULL) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ *signature = strdup(s);
|
|
+ dbus_free(s);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int sd_bus_message_readv(sd_bus_message *msg, const char *signature, va_list ap) {
|
|
+ // Immediately return 0 if there are not arguments to read.
|
|
+ if (dbus_message_iter_get_arg_type(msg->iter) == DBUS_TYPE_INVALID) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ DBusSignatureIter iter;
|
|
+ dbus_signature_iter_init(&iter, signature);
|
|
+ do {
|
|
+ // Bail out if the signature contains a non-basic type.
|
|
+ int type = dbus_signature_iter_get_current_type(&iter);
|
|
+ if (!dbus_type_is_basic(type)) {
|
|
+ va_end(ap);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Bail out if signature does not match the actual argument.
|
|
+ if (dbus_message_iter_get_arg_type(msg->iter) != type) {
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
+ // Read the value.
|
|
+ DBusBasicValue *ptr = va_arg(ap, DBusBasicValue *);
|
|
+ if (ptr != NULL) {
|
|
+ dbus_message_iter_get_basic(msg->iter, ptr);
|
|
+ }
|
|
+
|
|
+ // Don't check for "no more args" condition here, since it is possible
|
|
+ // that there are no more elements in the signature either. The erronous
|
|
+ // "signature not ended, but no more args" scenario is dealt with at the
|
|
+ // beginning of the loop body by DBUS_TYPE_INVALID not being a basic
|
|
+ // type.
|
|
+ dbus_message_iter_next(msg->iter);
|
|
+ } while (dbus_signature_iter_next(&iter));
|
|
+
|
|
+ return dbus_message_iter_has_next(msg->iter);
|
|
+}
|
|
+
|
|
+int sd_bus_message_read(sd_bus_message *msg, const char *signature, ...) {
|
|
+ int ret = 0;
|
|
+ va_list ap;
|
|
+ va_start(ap, signature);
|
|
+
|
|
+ // NOTE: There is a difference here between the real sd_bus_message_read and
|
|
+ // this wrapper. We only support messages that
|
|
+ // - contain a variant type that contain only basic types,
|
|
+ // - or contain only basic types.
|
|
+ //
|
|
+ // This is currently enough for Mako, but I left this note in case this
|
|
+ // function needs to be expanded in the future.
|
|
+ if (strcmp(signature, "v") == 0) {
|
|
+ const char *inner_signature = va_arg(ap, char *);
|
|
+ sd_bus_message_enter_container(msg, 'v', inner_signature);
|
|
+ ret = sd_bus_message_readv(msg, inner_signature, ap);
|
|
+ sd_bus_message_exit_container(msg);
|
|
+ } else {
|
|
+ ret = sd_bus_message_readv(msg, signature, ap);
|
|
+ }
|
|
+
|
|
+ va_end(ap);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int sd_bus_message_skip(sd_bus_message *msg, const char *signature) {
|
|
+ // Immediately return 0 if there are not arguments to read.
|
|
+ if (dbus_message_iter_get_arg_type(msg->iter) == DBUS_TYPE_INVALID) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ DBusSignatureIter iter;
|
|
+ dbus_signature_iter_init(&iter, signature);
|
|
+ do {
|
|
+ // Bail out if the signature contains a non-basic type.
|
|
+ int type = dbus_signature_iter_get_current_type(&iter);
|
|
+ if (!dbus_type_is_basic(type)) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ // Bail out if signature does not match the actual argument.
|
|
+ if (dbus_message_iter_get_arg_type(msg->iter) != type) {
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
+ // Don't check for "no more args" condition here, since it is possible
|
|
+ // that there are no more elements in the signature either. The erronous
|
|
+ // "signature not ended, but no more args" scenario is dealt with at the
|
|
+ // beginning of the loop body by DBUS_TYPE_INVALID not being a basic
|
|
+ // type.
|
|
+ dbus_message_iter_next(msg->iter);
|
|
+ } while (dbus_signature_iter_next(&iter));
|
|
+
|
|
+ return dbus_message_iter_has_next(msg->iter);
|
|
+}
|
|
+
|
|
+int sd_bus_message_enter_container(sd_bus_message *msg, char type,
|
|
+ const char *signature) {
|
|
+ // Immediately return 0 if there are no arguments to read (or in this case,
|
|
+ // no container to enter), or -ENXIO if signature and actual argument type
|
|
+ // does not match.
|
|
+ int t = dbus_message_iter_get_arg_type(msg->iter);
|
|
+ if (t == DBUS_TYPE_INVALID) {
|
|
+ return 0;
|
|
+ } else if (t != type) {
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
+ // Allocate an iterator, recurse into it, and set it as the current iterator
|
|
+ // of the message.
|
|
+ struct msg_iter *sub_iter = malloc(sizeof(struct msg_iter));
|
|
+ if (sub_iter == NULL) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ dbus_message_iter_recurse(msg->iter, &sub_iter->iter);
|
|
+ wl_list_insert(msg->iters, &sub_iter->link);
|
|
+ msg->iter = &sub_iter->iter;
|
|
+
|
|
+ return dbus_message_iter_has_next(&sub_iter->iter);
|
|
+}
|
|
+
|
|
+int sd_bus_message_exit_container(sd_bus_message *msg) {
|
|
+ // Remove the iterator we want to exit from from the iterator stack
|
|
+ struct msg_iter *iter = wl_container_of(msg->iters->next, iter, link);
|
|
+ wl_list_remove(&iter->link);
|
|
+
|
|
+ // Set msg's current iterator to the top of the iterator stack, and use
|
|
+ // dbus_message_iter_next to "step over" the iterator we are exiting.
|
|
+ iter = wl_container_of(msg->iters->next, iter, link);
|
|
+ msg->iter = &iter->iter;
|
|
+ dbus_message_iter_next(msg->iter);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface,
|
|
+ const char *name, const char *signature, ...) {
|
|
+ int ret = 0;
|
|
+ va_list ap;
|
|
+ va_start(ap, signature);
|
|
+
|
|
+ DBusMessage *signal = NULL;
|
|
+ if ((signal = dbus_message_new_signal(path, interface, name)) == NULL) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+ DBusSignatureIter signature_iter;
|
|
+ DBusMessageIter message_iter;
|
|
+ dbus_signature_iter_init(&signature_iter, signature);
|
|
+ dbus_message_iter_init_append(signal, &message_iter);
|
|
+ do {
|
|
+ int type = dbus_signature_iter_get_current_type(&signature_iter);
|
|
+ if (!dbus_type_is_basic(type)) {
|
|
+ ret = -EINVAL;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+ DBusBasicValue val = va_arg(ap, DBusBasicValue);
|
|
+ if (!dbus_message_iter_append_basic(&message_iter, type, &val)) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ } while (dbus_signature_iter_next(&signature_iter));
|
|
+
|
|
+ if (!dbus_connection_send(bus, signal, NULL)) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+finish:
|
|
+ va_end(ap);
|
|
+ dbus_message_unref(signal);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int sd_bus_reply_method_return(sd_bus_message *msg, const char *signature, ...) {
|
|
+ int ret = 0;
|
|
+ va_list ap;
|
|
+ va_start(ap, signature);
|
|
+
|
|
+ DBusMessage *reply = NULL;
|
|
+ if ((reply = dbus_message_new_method_return(msg->message)) == NULL) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+ if (strlen(signature) == 0) {
|
|
+ goto send;
|
|
+ }
|
|
+
|
|
+ DBusSignatureIter signature_iter;
|
|
+ DBusMessageIter message_iter;
|
|
+ dbus_signature_iter_init(&signature_iter, signature);
|
|
+ dbus_message_iter_init_append(reply, &message_iter);
|
|
+ do {
|
|
+ int type = dbus_signature_iter_get_current_type(&signature_iter);
|
|
+ if (!dbus_type_is_basic(type)) {
|
|
+ ret = -EINVAL;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+ DBusBasicValue val = va_arg(ap, DBusBasicValue);
|
|
+ if (!dbus_message_iter_append_basic(&message_iter, type, &val)) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ } while (dbus_signature_iter_next(&signature_iter));
|
|
+
|
|
+send:
|
|
+ if (!dbus_connection_send(msg->bus, reply, NULL)) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+finish:
|
|
+ va_end(ap);
|
|
+ dbus_message_unref(reply);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int sd_bus_send(sd_bus *bus, sd_bus_message *msg, dbus_uint32_t *cookie) {
|
|
+ // NOTE: The original sd_bus_send takes an uint64_t * as the third parameter.
|
|
+ // We take a dbus_uint32_t *, because dbus_connection_send uses it.
|
|
+
|
|
+ sd_bus *conn = (bus == NULL ? msg->bus : bus);
|
|
+ if (!dbus_connection_send(conn, msg->message, cookie)) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/dbus/subd-vtable.c b/dbus/subd-vtable.c
|
|
new file mode 100644
|
|
index 0000000..91b7c0e
|
|
--- /dev/null
|
|
+++ b/dbus/subd-vtable.c
|
|
@@ -0,0 +1,337 @@
|
|
+#include <errno.h>
|
|
+#include <stdbool.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include "subd.h"
|
|
+
|
|
+struct vtable_userdata {
|
|
+ struct wl_list *interfaces;
|
|
+ void *userdata;
|
|
+};
|
|
+
|
|
+struct interface {
|
|
+ const char *name;
|
|
+ const struct subd_member *members;
|
|
+ struct wl_list link;
|
|
+};
|
|
+
|
|
+struct path {
|
|
+ const char *path;
|
|
+ char *introspection_data;
|
|
+ struct wl_list *interfaces;
|
|
+ struct wl_list link;
|
|
+};
|
|
+
|
|
+static struct wl_list *paths = NULL;
|
|
+
|
|
+static bool add_args(FILE *stream, const char *sig, const char *end) {
|
|
+ DBusSignatureIter iter;
|
|
+ if (!dbus_signature_validate(sig, NULL)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (strlen(sig) > 0) {
|
|
+ dbus_signature_iter_init(&iter, sig);
|
|
+ do {
|
|
+ char *s = dbus_signature_iter_get_signature(&iter);
|
|
+ fprintf(stream, " <arg type=\"%s\" %s />\n", s, end);
|
|
+ dbus_free(s);
|
|
+ } while (dbus_signature_iter_next(&iter));
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static const char *generate_introspection_data(struct path *path) {
|
|
+ free(path->introspection_data);
|
|
+
|
|
+ size_t size;
|
|
+ FILE *stream = open_memstream(&path->introspection_data, &size);
|
|
+ if (stream == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ // Write the DOCTYPE entity, and start the <node> element.
|
|
+ fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE, stream);
|
|
+ fputs("<node>\n", stream);
|
|
+
|
|
+ // Iterate through the path's interfaces, ...
|
|
+ struct interface *interface;
|
|
+ wl_list_for_each(interface, path->interfaces, link) {
|
|
+ fprintf(stream, " <interface name=\"%s\">\n", interface->name);
|
|
+
|
|
+ const struct subd_member *member = interface->members;
|
|
+ while (member->type != SUBD_MEMBERS_END) {
|
|
+ switch (member->type) {
|
|
+ case SUBD_METHOD:
|
|
+ fprintf(stream, " <method name=\"%s\">\n", member->m.name);
|
|
+ add_args(stream, member->m.input_signature, "direction=\"in\"");
|
|
+ add_args(stream, member->m.output_signature, "direction=\"out\"");
|
|
+ fprintf(stream, " </method>\n");
|
|
+ break;
|
|
+ case SUBD_SIGNAL:
|
|
+ fprintf(stream, " <signal name=\"%s\">\n", member->s.name);
|
|
+ add_args(stream, member->s.signature, "");
|
|
+ fprintf(stream, " </signal>\n");
|
|
+ break;
|
|
+ case SUBD_PROPERTY:
|
|
+ fprintf(stream, " <property name=\"%s\" type=\"%s\" ",
|
|
+ member->p.name, member->p.signature);
|
|
+ switch (member->p.access) {
|
|
+ case SUBD_PROPERTY_READ:
|
|
+ fprintf(stream, "\"read\" />\n");
|
|
+ break;
|
|
+ case SUBD_PROPERTY_WRITE:
|
|
+ fprintf(stream, "\"write\" />\n");
|
|
+ break;
|
|
+ case SUBD_PROPERTY_READWRITE:
|
|
+ fprintf(stream, "\"readwrite\" />\n");
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case SUBD_MEMBERS_END:
|
|
+ // not gonna happen
|
|
+ break;
|
|
+ }
|
|
+ member++;
|
|
+ }
|
|
+ fprintf(stream, " </interface>\n");
|
|
+ }
|
|
+ fprintf(stream, "</node>");
|
|
+ fclose(stream);
|
|
+
|
|
+ return path->introspection_data;
|
|
+}
|
|
+
|
|
+static int handle_introspect(sd_bus_message *msg, void *data, sd_bus_error *err) {
|
|
+ // Find the path the message was sent to, so we can access its list of
|
|
+ // implemented interfaces.
|
|
+ const char *path_name = dbus_message_get_path(msg->message);
|
|
+ struct path *p, *path = NULL;
|
|
+ wl_list_for_each(p, paths, link) {
|
|
+ if (strcmp(p->path, path_name) == 0) {
|
|
+ path = p;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (path == NULL) {
|
|
+ // Something is seriously weird here. Path was not found, but then how
|
|
+ // was the method handler called??
|
|
+ dbus_set_error(err, DBUS_ERROR_INVALID_ARGS,
|
|
+ "Path was not found in paths list.");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (path->introspection_data == NULL) {
|
|
+ // This shouldn't really happen, introspection data is generated when
|
|
+ // the vtable is registered.
|
|
+ if (generate_introspection_data(path) == NULL) {
|
|
+ dbus_set_error(err, DBUS_ERROR_NO_MEMORY,
|
|
+ "Introspection data could not be generated.");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return sd_bus_reply_method_return(msg, "s", path->introspection_data);
|
|
+}
|
|
+
|
|
+static const struct subd_member introspectable_members[] = {
|
|
+ {SUBD_METHOD, .m = {"Introspect", handle_introspect, "", "s"}},
|
|
+ {SUBD_MEMBERS_END, .e=0},
|
|
+};
|
|
+
|
|
+/**
|
|
+ * Helper function for vtable_dispatch that returns wither NULL, or the method
|
|
+ * object member with the name "name".
|
|
+ */
|
|
+static const struct subd_member *find_member(const struct subd_member *members,
|
|
+ const char *name) {
|
|
+ const struct subd_member *member = members;
|
|
+ while (member->type != SUBD_MEMBERS_END) {
|
|
+ if (member->type == SUBD_METHOD && strcmp(member->m.name, name) == 0) {
|
|
+ return member;
|
|
+ }
|
|
+ ++member;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Helper function for vtable_dispatch that calls the method object member's
|
|
+ * handler function, and sends an error message if necessary.
|
|
+ */
|
|
+static bool call_method(const struct subd_member *member, DBusConnection *conn,
|
|
+ DBusMessage *msg, void *userdata) {
|
|
+ sd_bus_message *message = NULL;
|
|
+ message = malloc(sizeof(sd_bus_message));
|
|
+ if (message == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+ message->bus = conn;
|
|
+ message->message = msg;
|
|
+ message->ref_count = 1;
|
|
+ message->iters = malloc(sizeof(struct wl_list));
|
|
+ if (message->iters == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+ wl_list_init(message->iters);
|
|
+
|
|
+ struct msg_iter *iter = malloc(sizeof(struct msg_iter));
|
|
+ if (iter == NULL) {
|
|
+ return false;
|
|
+ }
|
|
+ dbus_message_iter_init(message->message, &iter->iter);
|
|
+ wl_list_insert(message->iters, &iter->link);
|
|
+ message->iter = &iter->iter;
|
|
+
|
|
+ DBusError error;
|
|
+ dbus_error_init(&error);
|
|
+ if (member->m.handler(message, userdata, &error) < 0) {
|
|
+ //XXX: handle error == NULL
|
|
+ DBusMessage *error_message =
|
|
+ dbus_message_new_error(msg, error.name, error.message);
|
|
+ dbus_connection_send(conn, error_message, 0);
|
|
+ dbus_error_free(&error);
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * This function receives a list of interfaces implemented by the destination
|
|
+ * object in "userdata->interfaces", and iterates through them and their members
|
|
+ * to find the called method. When the method is found, its handler function is
|
|
+ * called with "data" set to "userdata->userdata".
|
|
+ */
|
|
+static DBusHandlerResult vtable_dispatch(DBusConnection *connection,
|
|
+ DBusMessage *message, void *userdata) {
|
|
+ struct vtable_userdata *data = userdata;
|
|
+ const char *interface_name = dbus_message_get_interface(message);
|
|
+ const char *member_name = dbus_message_get_member(message);
|
|
+ if (interface_name == NULL || member_name == NULL) {
|
|
+ // something is wrong, no need to try with other handlers
|
|
+ return DBUS_HANDLER_RESULT_HANDLED;
|
|
+ }
|
|
+
|
|
+ struct interface *interface;
|
|
+ wl_list_for_each(interface, data->interfaces, link) {
|
|
+ if (strcmp(interface->name, interface_name) == 0) {
|
|
+ const struct subd_member *member =
|
|
+ find_member(interface->members, member_name);
|
|
+ if (member != NULL) {
|
|
+ call_method(member, connection, message, data->userdata);
|
|
+ return DBUS_HANDLER_RESULT_HANDLED;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
+}
|
|
+
|
|
+static const DBusObjectPathVTable dbus_vtable = {
|
|
+ .message_function = vtable_dispatch,
|
|
+ .unregister_function = NULL,
|
|
+};
|
|
+
|
|
+int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot,
|
|
+ const char *path_name, const char *interface,
|
|
+ const sd_bus_vtable *vtable, void *userdata) {
|
|
+ int ret = 0;
|
|
+
|
|
+ if (paths == NULL) {
|
|
+ paths = malloc(sizeof(struct path));
|
|
+ if (paths == NULL) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ wl_list_init(paths);
|
|
+ }
|
|
+
|
|
+ // See if this path is already registered. If it is, it must have at least
|
|
+ // one interface, so get a pointer to the interfaces list.
|
|
+ struct wl_list *interfaces = NULL;
|
|
+ struct path *p, *path = NULL;
|
|
+ wl_list_for_each(p, paths, link) {
|
|
+ if (strcmp(path_name, p->path) == 0) {
|
|
+ path = p;
|
|
+ interfaces = p->interfaces;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (interfaces == NULL) {
|
|
+ // Path was not registered before, so first we create an interface list,
|
|
+ // and append Introspectable to it. We want every path to implement
|
|
+ // org.freedesktop.DBus.Introspectable.
|
|
+ // TODO: Also implement the following:
|
|
+ // - org.freedesktop.DBus.Peer
|
|
+ // - org.freedesktop.DBus.Properties
|
|
+ interfaces = malloc(sizeof(struct wl_list));
|
|
+ if (interfaces == NULL) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ wl_list_init(interfaces);
|
|
+ struct interface *new_interface = malloc(sizeof(struct interface));
|
|
+ if (interface == NULL) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ new_interface->name = strdup("org.freedesktop.DBus.Introspectable");
|
|
+ new_interface->members = introspectable_members;
|
|
+ wl_list_insert(interfaces, &new_interface->link);
|
|
+
|
|
+ // Create the path with the new interface list
|
|
+ struct path *new_path = malloc(sizeof(struct path));
|
|
+ if (new_path == NULL) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ new_path->path = strdup(path_name);
|
|
+ new_path->interfaces = interfaces;
|
|
+ new_path->introspection_data = NULL; // This will be set later.
|
|
+ path = new_path;
|
|
+
|
|
+ // ... and also register it.
|
|
+ // We merge userdata with the interfaces list in a struct
|
|
+ // vtable_userdata here, so vtable_dispatch will know what interfaces to
|
|
+ // traverse, and what userdata to pass to the actual handler functions.
|
|
+ struct vtable_userdata *data = malloc(sizeof(struct vtable_userdata));
|
|
+ if (data == NULL) {
|
|
+ free(new_path);
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ data->interfaces = interfaces;
|
|
+ data->userdata = userdata;
|
|
+ if (!dbus_connection_try_register_object_path(bus, path_name,
|
|
+ &dbus_vtable, data, NULL)) {
|
|
+ free(new_path);
|
|
+ ret = -ENXIO;
|
|
+ goto finish;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //TODO: Decide what to do if interface is already registered. Replace
|
|
+ //memeber list? Append new members to list? Throw an error?
|
|
+
|
|
+ // Append the new interface to the path's interface list.
|
|
+ struct interface *new_interface = malloc(sizeof(struct interface));
|
|
+ if (new_interface == NULL) {
|
|
+ ret = -ENOMEM;
|
|
+ goto finish;
|
|
+ }
|
|
+ new_interface->name = strdup(interface);
|
|
+ new_interface->members = vtable;
|
|
+ wl_list_insert(interfaces, &new_interface->link);
|
|
+
|
|
+ // Append the path to the list of paths
|
|
+ wl_list_insert(paths, &path->link);
|
|
+
|
|
+ // (Re)generate introspection XML for this path.
|
|
+ generate_introspection_data(path);
|
|
+
|
|
+finish:
|
|
+ return ret;
|
|
+}
|
|
diff --git a/dbus/subd-watch.c b/dbus/subd-watch.c
|
|
new file mode 100644
|
|
index 0000000..ef913e7
|
|
--- /dev/null
|
|
+++ b/dbus/subd-watch.c
|
|
@@ -0,0 +1,180 @@
|
|
+#include <errno.h>
|
|
+#include <poll.h>
|
|
+#include <semaphore.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include "subd.h"
|
|
+
|
|
+static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
|
|
+ struct subd_watches *watches = data;
|
|
+ sem_wait(&watches->mutex);
|
|
+
|
|
+ if (!dbus_watch_get_enabled(watch)) {
|
|
+ sem_post(&watches->mutex);
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ if (watches->length == watches->capacity) {
|
|
+ int c = watches->capacity + 10;
|
|
+ void *t1 = realloc(watches->fds, sizeof(struct pollfd) * c);
|
|
+ void *t2 = realloc(watches->watches, sizeof(DBusWatch *) * c);
|
|
+ if (t1 == NULL || t2 == NULL) {
|
|
+ sem_post(&watches->mutex);
|
|
+ return FALSE;
|
|
+ } else {
|
|
+ watches->capacity = c;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ short mask = 0;
|
|
+ unsigned int flags = dbus_watch_get_flags(watch);
|
|
+ if (flags & DBUS_WATCH_READABLE) {
|
|
+ mask |= POLLIN;
|
|
+ }
|
|
+ if (flags & DBUS_WATCH_WRITABLE) {
|
|
+ mask |= POLLOUT;
|
|
+ }
|
|
+
|
|
+ int fd = dbus_watch_get_unix_fd(watch);
|
|
+ struct pollfd pollfd = {fd, mask, 0};
|
|
+ int index = watches->length++;
|
|
+ watches->fds[index] = pollfd;
|
|
+ watches->watches[index] = watch;
|
|
+
|
|
+ sem_post(&watches->mutex);
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+static void remove_watch(DBusWatch *watch, void *data) {
|
|
+ struct subd_watches *watches = data;
|
|
+ sem_wait(&watches->mutex);
|
|
+
|
|
+ int index = -1;
|
|
+ for (int i = 0; i < watches->length; ++i) {
|
|
+ if (watches->watches[i] == watch) {
|
|
+ index = i;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (index != -1) {
|
|
+ --watches->length;
|
|
+ memmove(&watches->fds[index], &watches->fds[index + 1],
|
|
+ sizeof(struct pollfd) * watches->length - index);
|
|
+ memmove(&watches->watches[index], &watches->watches[index + 1],
|
|
+ sizeof(DBusWatch *) * watches->length - index);
|
|
+ }
|
|
+
|
|
+ sem_post(&watches->mutex);
|
|
+}
|
|
+
|
|
+static void toggle_watch(DBusWatch *watch, void *data) {
|
|
+ if (dbus_watch_get_enabled(watch)) {
|
|
+ add_watch(watch, data);
|
|
+ } else {
|
|
+ remove_watch(watch, data);
|
|
+ }
|
|
+}
|
|
+
|
|
+struct subd_watches *subd_init_watches(struct DBusConnection *connection,
|
|
+ struct pollfd *fds, int size, DBusError *error) {
|
|
+ const char *error_code = NULL;
|
|
+
|
|
+ // Initialize the watches structure.
|
|
+ struct subd_watches *watches = malloc(sizeof(struct subd_watches));
|
|
+ if (watches == NULL) {
|
|
+ error_code = DBUS_ERROR_NO_MEMORY;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ watches->capacity = 10 + size;
|
|
+ watches->length = size;
|
|
+ watches->fds = malloc(watches->capacity * sizeof(struct pollfd));
|
|
+ watches->watches = malloc(watches->capacity * sizeof(DBusWatch*));
|
|
+ if (watches->fds == NULL || watches->watches == NULL) {
|
|
+ error_code = DBUS_ERROR_NO_MEMORY;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ // Initialize a semaphore for the watches. It is needed to prevent the add,
|
|
+ // remove and toggle functions accessing the watch storage while it is being
|
|
+ // processed by subd_process_watches.
|
|
+ if (sem_init(&watches->mutex, 0, 1) == -1) {
|
|
+ if (errno == EINVAL) {
|
|
+ error_code = DBUS_ERROR_INVALID_ARGS;
|
|
+ } else {
|
|
+ error_code = DBUS_ERROR_NO_MEMORY;
|
|
+ }
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ // Add any non-dbus file descriptors.
|
|
+ for (int i = 0; i < size; ++i) {
|
|
+ watches->fds[i] = (struct pollfd){
|
|
+ .fd = fds->fd,
|
|
+ .events = fds->events
|
|
+ };
|
|
+ watches->watches[i] = NULL;
|
|
+ ++fds;
|
|
+ }
|
|
+
|
|
+ // Register the add, remove, and toggle functions.
|
|
+ // NOTE: Can't use the free_data_function argument to automatically free
|
|
+ // watches when connection finalizes, because sometimes it does not work.
|
|
+ if (!dbus_connection_set_watch_functions(connection, add_watch,
|
|
+ remove_watch, toggle_watch, watches, NULL)) {
|
|
+ error_code = DBUS_ERROR_NO_MEMORY;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ return watches;
|
|
+
|
|
+error:
|
|
+ if (watches != NULL) {
|
|
+ if (watches->fds != NULL) {
|
|
+ free(watches->fds);
|
|
+ }
|
|
+ if (watches->watches != NULL) {
|
|
+ free(watches->watches);
|
|
+ }
|
|
+ }
|
|
+ dbus_set_error(error, error_code, NULL);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void subd_process_watches(DBusConnection *conn, struct subd_watches *watches) {
|
|
+ sem_wait(&watches->mutex);
|
|
+
|
|
+ for (int i = 0; i < watches->length; ++i) {
|
|
+ struct pollfd pollfd = watches->fds[i];
|
|
+ DBusWatch *watch = watches->watches[i];
|
|
+
|
|
+ if (watch == NULL || !dbus_watch_get_enabled(watch)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (pollfd.revents & pollfd.events) {
|
|
+ unsigned int flags = 0;
|
|
+ if (pollfd.revents & POLLIN) {
|
|
+ flags |= DBUS_WATCH_READABLE;
|
|
+ }
|
|
+ if (pollfd.revents & POLLOUT) {
|
|
+ flags |= DBUS_WATCH_WRITABLE;
|
|
+ }
|
|
+ if (pollfd.revents & POLLHUP) {
|
|
+ flags |= DBUS_WATCH_HANGUP;
|
|
+ }
|
|
+ if (pollfd.revents & POLLERR) {
|
|
+ flags |= DBUS_WATCH_ERROR;
|
|
+ }
|
|
+
|
|
+ //TODO: Error handling. Not sure, what is the right move here. Log
|
|
+ // and ignore? Make them fatal?
|
|
+ dbus_watch_handle(watch, flags);
|
|
+ while (dbus_connection_dispatch(conn) ==
|
|
+ DBUS_DISPATCH_DATA_REMAINS);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ sem_post(&watches->mutex);
|
|
+}
|
|
diff --git a/include/subd-sdbus.h b/include/subd-sdbus.h
|
|
new file mode 100644
|
|
index 0000000..8d77600
|
|
--- /dev/null
|
|
+++ b/include/subd-sdbus.h
|
|
@@ -0,0 +1,142 @@
|
|
+#ifndef _SUBD_SDBUS_H
|
|
+#define _SUBD_SDBUS_H
|
|
+
|
|
+#include <dbus/dbus.h>
|
|
+#include <wayland-util.h>
|
|
+
|
|
+#define SD_BUS_NAME_ALLOW_REPLACEMENT DBUS_NAME_FLAG_ALLOW_REPLACEMENT
|
|
+#define SD_BUS_NAME_REPLACE_EXISTING DBUS_NAME_FLAG_REPLACE_EXISTING
|
|
+#define SD_BUS_NAME_QUEUE ~DBUS_NAME_FLAG_DO_NOT_QUEUE
|
|
+
|
|
+/**
|
|
+ * These types are the rough equivalents of each other in libdbus and sd-bus.
|
|
+ * They are opaque structures in both library, so we can just typedef them to
|
|
+ * make our life easier.
|
|
+ */
|
|
+typedef struct DBusConnection sd_bus;
|
|
+typedef struct DBusError sd_bus_error;
|
|
+typedef struct subd_member sd_bus_vtable;
|
|
+
|
|
+/**
|
|
+ * his is not used, but typedef-d to preserve sd-bus function signatures.
|
|
+ */
|
|
+typedef int sd_bus_slot;
|
|
+
|
|
+/**
|
|
+ * In sd-bus, sd_bus_message knows what sd_bus it is associated with, and also
|
|
+ * keeps track of its current read/write position. This can be achieved with
|
|
+ * libdbus by encapsulating the DBusConnection (sd_bus), the DBusMessage, and a
|
|
+ * stack of iterators (implemented here as a wl_list of msg_iter structs) in one
|
|
+ * structure. The current DBusMessageIter (iter) is also stored to make
|
|
+ * accessing it easier (i.e. it's just syntactic sugar).
|
|
+ */
|
|
+struct msg_iter {
|
|
+ DBusMessageIter iter;
|
|
+ struct wl_list link;
|
|
+};
|
|
+
|
|
+typedef struct sd_bus_message {
|
|
+ sd_bus *bus;
|
|
+ DBusMessage *message;
|
|
+ DBusMessageIter *iter;
|
|
+ struct wl_list *iters;
|
|
+ int ref_count;
|
|
+} sd_bus_message;
|
|
+
|
|
+/**
|
|
+ * The following two enums and one struct are pulled straight from subd, and are
|
|
+ * used by the handler dispatcher logic, and the automatic Introspectable
|
|
+ * intarface implementation.
|
|
+ *
|
|
+ * TODO: These could be changed to behave the same as sd-bus vtables, which
|
|
+ * would eliminate the need of #ifdef-d vtable definitions in dbus/xdg.c and
|
|
+ * dbus/mako.c.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * Represents the three DBus member types.
|
|
+ */
|
|
+enum subd_member_type {
|
|
+ SUBD_METHOD,
|
|
+ SUBD_SIGNAL,
|
|
+ SUBD_PROPERTY,
|
|
+ SUBD_MEMBERS_END,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * Represents the three possible access types for DBus properties.
|
|
+ */
|
|
+enum subd_property_access {
|
|
+ SUBD_PROPERTY_READ,
|
|
+ SUBD_PROPERTY_WRITE,
|
|
+ SUBD_PROPERTY_READWRITE,
|
|
+};
|
|
+
|
|
+/**
|
|
+ * This struct represents a DBus object member, and serves two purpose:
|
|
+ *
|
|
+ * - If the member is a method, it has a pointer to the method's handler
|
|
+ * function, so that the vtable dispatcher knows where to dispatch execution.
|
|
+ * - It has the metadata for the member (name, output and/or input signatures,
|
|
+ * access) that introspection data can be built from.
|
|
+ */
|
|
+struct subd_member {
|
|
+ enum subd_member_type type;
|
|
+ union {
|
|
+ struct {
|
|
+ const char *name;
|
|
+ int (*handler)(sd_bus_message *, void *, sd_bus_error *);
|
|
+ const char *input_signature;
|
|
+ const char *output_signature;
|
|
+ } m;
|
|
+ struct {
|
|
+ const char *name;
|
|
+ const char *signature;
|
|
+ } s;
|
|
+ struct {
|
|
+ const char *name;
|
|
+ const char *signature;
|
|
+ enum subd_property_access access;
|
|
+ } p;
|
|
+ int e;
|
|
+ };
|
|
+};
|
|
+
|
|
+/**
|
|
+ * The following functions are wrappers around the libdbus library that mimic
|
|
+ * their sd-bus equivalents. These are not necessarily 1:1 matches of the
|
|
+ * originals, only the functionality needed for mako is implemented here.
|
|
+ * Most notable difference is that functions that read or write messages are
|
|
+ * only able to deal with basic types.
|
|
+ */
|
|
+
|
|
+int sd_bus_open_user(sd_bus **bus);
|
|
+int sd_bus_request_name(sd_bus *bus, const char *name, int flags);
|
|
+void sd_bus_slot_unref(int *slot);
|
|
+void sd_bus_flush_close_unref(sd_bus *bus);
|
|
+
|
|
+void sd_bus_error_set_const(sd_bus_error *err, const char *name, const char *msg);
|
|
+
|
|
+int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newmsg);
|
|
+int sd_bus_message_open_container(sd_bus_message *msg, char type,
|
|
+ const char *signature);
|
|
+int sd_bus_message_append(sd_bus_message *msg, const char *signature, ...);
|
|
+int sd_bus_message_close_container(sd_bus_message *msg);
|
|
+int sd_bus_message_peek_type(sd_bus_message *msg, void *unused,
|
|
+ const char **signature);
|
|
+int sd_bus_message_read(sd_bus_message *msg, const char *signature, ...);
|
|
+int sd_bus_message_enter_container(sd_bus_message *msg, char type,
|
|
+ const char *signature);
|
|
+int sd_bus_message_exit_container(sd_bus_message *msg);
|
|
+int sd_bus_message_skip(sd_bus_message *msg, const char *signature);
|
|
+void sd_bus_message_unref(sd_bus_message *msg);
|
|
+
|
|
+int sd_bus_emit_signal(sd_bus *bus, const char *path, const char *interface,
|
|
+ const char *name, const char *signature, ...);
|
|
+int sd_bus_reply_method_return(sd_bus_message *msg, const char *signature, ...);
|
|
+int sd_bus_send(sd_bus *bus, sd_bus_message *msg, dbus_uint32_t *cookie);
|
|
+
|
|
+int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path_name,
|
|
+ const char *interface, const sd_bus_vtable *vtable, void *data);
|
|
+
|
|
+#endif
|
|
diff --git a/include/subd.h b/include/subd.h
|
|
new file mode 100644
|
|
index 0000000..33c997b
|
|
--- /dev/null
|
|
+++ b/include/subd.h
|
|
@@ -0,0 +1,41 @@
|
|
+#ifndef _SUBD_H
|
|
+#define _SUBD_H
|
|
+
|
|
+#include <semaphore.h>
|
|
+#include "subd-sdbus.h"
|
|
+
|
|
+struct pollfd;
|
|
+
|
|
+/**
|
|
+ * This struct stores the DBus watches, and their corresponging file
|
|
+ * descriptors. This will be auto-updated whenever DBus needs additional file
|
|
+ * descriptors to watch. You can also store other, not DBus-related file
|
|
+ * descriptors here, so you can directly use fds as a parameter for poll().
|
|
+ * If you add non-watch file descriptors, make sure to set their corresponding
|
|
+ * watch to NULL, so that #subd_process_watches knows to skip them.
|
|
+ */
|
|
+struct subd_watches {
|
|
+ struct pollfd *fds;
|
|
+ DBusWatch **watches;
|
|
+ int capacity;
|
|
+ int length;
|
|
+ sem_t mutex;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * This function creates a subd_watches instance, and pre-populates it with
|
|
+ * the non-DBus file descriptors passed as fds. It also registers the add,
|
|
+ * remove and toggle functions that will handle automatic file descriptor
|
|
+ * additions/removals.
|
|
+ */
|
|
+struct subd_watches *subd_init_watches(DBusConnection *conn, struct pollfd *fds,
|
|
+ int size, DBusError *error);
|
|
+
|
|
+/**
|
|
+ * This function should be called from the event loop after a successful poll to
|
|
+ * handle the DBus watches that need to be handled (= the watches whose file
|
|
+ * descriptor returned an event).
|
|
+ */
|
|
+void subd_process_watches(DBusConnection *conn, struct subd_watches *watches);
|
|
+
|
|
+#endif
|
|
|
|
From 5ed385e6ddf97378b9a61295fe77216a3525c394 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 26 Oct 2018 15:52:04 +0200
|
|
Subject: [PATCH 02/17] Add conditionally compiled code pieces for subd
|
|
|
|
This commit adds necessary modifications to the original Mako code, and
|
|
puts them behind preprocessor conditions defined by the build system.
|
|
---
|
|
dbus/mako.c | 10 +++++++++
|
|
dbus/xdg.c | 12 +++++++++++
|
|
event-loop.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
|
|
include/dbus.h | 2 ++
|
|
include/event-loop.h | 9 ++++++++
|
|
include/mako.h | 2 ++
|
|
6 files changed, 85 insertions(+)
|
|
|
|
diff --git a/dbus/mako.c b/dbus/mako.c
|
|
index 2b78ac6..c14f146 100644
|
|
--- a/dbus/mako.c
|
|
+++ b/dbus/mako.c
|
|
@@ -92,6 +92,7 @@ static int handle_reload(sd_bus_message *msg, void *data,
|
|
return sd_bus_reply_method_return(msg, "");
|
|
}
|
|
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
static const sd_bus_vtable service_vtable[] = {
|
|
SD_BUS_VTABLE_START(0),
|
|
SD_BUS_METHOD("DismissAllNotifications", "", "", handle_dismiss_all_notifications, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
@@ -100,6 +101,15 @@ static const sd_bus_vtable service_vtable[] = {
|
|
SD_BUS_METHOD("Reload", "", "", handle_reload, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
SD_BUS_VTABLE_END
|
|
};
|
|
+#else
|
|
+static const struct subd_member service_vtable[] = {
|
|
+ {SUBD_METHOD, .m = {"DismissAllNotifications", handle_dismiss_all_notifications, "", ""}},
|
|
+ {SUBD_METHOD, .m = {"DismissLastNotification", handle_dismiss_last_notification, "", ""}},
|
|
+ {SUBD_METHOD, .m = {"InvokeAction", handle_invoke_action, "s", ""}},
|
|
+ {SUBD_METHOD, .m = {"Reload", handle_reload, "", ""}},
|
|
+ {SUBD_MEMBERS_END, .e=0},
|
|
+};
|
|
+#endif
|
|
|
|
int init_dbus_mako(struct mako_state *state) {
|
|
return sd_bus_add_object_vtable(state->bus, &state->mako_slot, service_path,
|
|
diff --git a/dbus/xdg.c b/dbus/xdg.c
|
|
index 66c2a9e..ab4abae 100644
|
|
--- a/dbus/xdg.c
|
|
+++ b/dbus/xdg.c
|
|
@@ -275,6 +275,7 @@ static int handle_get_server_information(sd_bus_message *msg, void *data,
|
|
spec_version);
|
|
}
|
|
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
static const sd_bus_vtable service_vtable[] = {
|
|
SD_BUS_VTABLE_START(0),
|
|
SD_BUS_METHOD("GetCapabilities", "", "as", handle_get_capabilities, SD_BUS_VTABLE_UNPRIVILEGED),
|
|
@@ -285,6 +286,17 @@ static const sd_bus_vtable service_vtable[] = {
|
|
SD_BUS_SIGNAL("NotificationClosed", "uu", 0),
|
|
SD_BUS_VTABLE_END
|
|
};
|
|
+#else
|
|
+static const struct subd_member service_vtable[] = {
|
|
+ {SUBD_METHOD, .m = {"GetCapabilities", handle_get_capabilities, "", "as"}},
|
|
+ {SUBD_METHOD, .m = {"Notify", handle_notify, "susssasa{sv}i", "u"}},
|
|
+ {SUBD_METHOD, .m = {"CloseNotification", handle_close_notification, "u", ""}},
|
|
+ {SUBD_METHOD, .m = {"GetServerInformation", handle_get_server_information, "", "ssss"}},
|
|
+ {SUBD_SIGNAL, .s = {"ActionInvoked", "us"}},
|
|
+ {SUBD_SIGNAL, .s = {"NotificationClosed", "uu"}},
|
|
+ {SUBD_MEMBERS_END, .e=0},
|
|
+};
|
|
+#endif
|
|
|
|
int init_dbus_xdg(struct mako_state *state) {
|
|
return sd_bus_add_object_vtable(state->bus, &state->xdg_slot, service_path,
|
|
diff --git a/event-loop.c b/event-loop.c
|
|
index aacfebf..4b6c02e 100644
|
|
--- a/event-loop.c
|
|
+++ b/event-loop.c
|
|
@@ -33,6 +33,7 @@ static int init_signalfd() {
|
|
return sfd;
|
|
}
|
|
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
bool init_event_loop(struct mako_event_loop *loop, sd_bus *bus,
|
|
struct wl_display *display) {
|
|
if ((loop->sfd = init_signalfd()) == -1) {
|
|
@@ -65,6 +66,47 @@ bool init_event_loop(struct mako_event_loop *loop, sd_bus *bus,
|
|
|
|
return true;
|
|
}
|
|
+#else
|
|
+bool init_event_loop(struct mako_event_loop *loop, sd_bus *bus,
|
|
+ struct wl_display *display) {
|
|
+ if ((loop->sfd = init_signalfd()) == -1) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ struct pollfd pollfds[MAKO_EVENT_COUNT];
|
|
+
|
|
+ pollfds[MAKO_EVENT_SIGNAL] = (struct pollfd){
|
|
+ .fd = loop->sfd;
|
|
+ .events = POLLIN,
|
|
+ };
|
|
+
|
|
+ pollfds[MAKO_EVENT_WAYLAND] = (struct pollfd){
|
|
+ .fd = wl_display_get_fd(display),
|
|
+ .events = POLLIN,
|
|
+ };
|
|
+
|
|
+ pollfds[MAKO_EVENT_TIMER] = (struct pollfd){
|
|
+ .fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC),
|
|
+ .events = POLLIN,
|
|
+ };
|
|
+
|
|
+ DBusError error;
|
|
+ dbus_error_init(&error);
|
|
+ loop->watches = subd_init_watches(connection, pollfds, MAKO_EVENT_COUNT,
|
|
+ &error);
|
|
+ if (loop->watches == NULL) {
|
|
+ fprintf(stderr, "failed to initialize loop: %s\n", error.message);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ loop->fds = loop->watches->fds;
|
|
+ loop->bus = connection;
|
|
+ loop->display = display;
|
|
+ wl_list_init(&loop->timers);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+#endif
|
|
|
|
void finish_event_loop(struct mako_event_loop *loop) {
|
|
close(loop->fds[MAKO_EVENT_TIMER].fd);
|
|
@@ -77,7 +119,11 @@ void finish_event_loop(struct mako_event_loop *loop) {
|
|
}
|
|
|
|
static int poll_event_loop(struct mako_event_loop *loop) {
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
return poll(loop->fds, MAKO_EVENT_COUNT, -1);
|
|
+#else
|
|
+ return poll(loop->fds, loop->watches->length, -1);
|
|
+#endif
|
|
}
|
|
|
|
static void timespec_add(struct timespec *t, int delta_ms) {
|
|
@@ -215,6 +261,7 @@ int run_event_loop(struct mako_event_loop *loop) {
|
|
wl_display_cancel_read(loop->display);
|
|
}
|
|
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
if (loop->fds[MAKO_EVENT_DBUS].revents & POLLIN) {
|
|
while (1) {
|
|
ret = sd_bus_process(loop->bus, NULL);
|
|
@@ -233,6 +280,9 @@ int run_event_loop(struct mako_event_loop *loop) {
|
|
break;
|
|
}
|
|
}
|
|
+#else
|
|
+ subd_process_watches(loop->bus, loop->watches);
|
|
+#endif
|
|
|
|
if (loop->fds[MAKO_EVENT_WAYLAND].revents & POLLIN) {
|
|
ret = wl_display_read_events(loop->display);
|
|
diff --git a/include/dbus.h b/include/dbus.h
|
|
index 550151e..f50d79e 100644
|
|
--- a/include/dbus.h
|
|
+++ b/include/dbus.h
|
|
@@ -6,6 +6,8 @@
|
|
#include <systemd/sd-bus.h>
|
|
#elif HAVE_ELOGIND
|
|
#include <elogind/sd-bus.h>
|
|
+#elif HAVE_SUBD
|
|
+#include "subd.h"
|
|
#endif
|
|
|
|
struct mako_state;
|
|
diff --git a/include/event-loop.h b/include/event-loop.h
|
|
index 460c711..85d05ce 100644
|
|
--- a/include/event-loop.h
|
|
+++ b/include/event-loop.h
|
|
@@ -9,10 +9,14 @@
|
|
#include <systemd/sd-bus.h>
|
|
#elif HAVE_ELOGIND
|
|
#include <elogind/sd-bus.h>
|
|
+#elif HAVE_SUBD
|
|
+#include "subd.h"
|
|
#endif
|
|
|
|
enum mako_event {
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
MAKO_EVENT_DBUS,
|
|
+#endif
|
|
MAKO_EVENT_WAYLAND,
|
|
MAKO_EVENT_TIMER,
|
|
MAKO_EVENT_SIGNAL,
|
|
@@ -20,7 +24,12 @@ enum mako_event {
|
|
};
|
|
|
|
struct mako_event_loop {
|
|
+#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
struct pollfd fds[MAKO_EVENT_COUNT];
|
|
+#else
|
|
+ struct subd_watches *watches;
|
|
+ struct pollfd *fds;
|
|
+#endif
|
|
sd_bus *bus;
|
|
struct wl_display *display;
|
|
int sfd;
|
|
diff --git a/include/mako.h b/include/mako.h
|
|
index 9b81545..82eb0e5 100644
|
|
--- a/include/mako.h
|
|
+++ b/include/mako.h
|
|
@@ -7,6 +7,8 @@
|
|
#include <systemd/sd-bus.h>
|
|
#elif HAVE_ELOGIND
|
|
#include <elogind/sd-bus.h>
|
|
+#elif HAVE_SUBD
|
|
+#include "subd.h"
|
|
#endif
|
|
|
|
#include "config.h"
|
|
|
|
From b9f3e39a7559934956cd43ba0c591d74047f3f3a Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 26 Oct 2018 17:07:20 +0200
|
|
Subject: [PATCH 03/17] Add dbus-1 as optional dependency
|
|
|
|
This commit adds the dbus-1 library as a dependency if neither systemd,
|
|
nor elogind is available. It also adds the sd-bus wrappers to the build
|
|
system in such case.
|
|
---
|
|
meson.build | 73 +++++++++++++++++++++++++++++------------------
|
|
meson_options.txt | 2 ++
|
|
2 files changed, 48 insertions(+), 27 deletions(-)
|
|
create mode 100644 meson_options.txt
|
|
|
|
diff --git a/meson.build b/meson.build
|
|
index 1eecabc..a92dbc7 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -19,43 +19,62 @@ mako_inc = include_directories('include')
|
|
cairo = dependency('cairo')
|
|
pango = dependency('pango')
|
|
pangocairo = dependency('pangocairo')
|
|
+sdbus = dependency(get_option('sdbus-provider'), required: get_option('sdbus'))
|
|
+dbus1 = dependency('dbus-1', required: not sdbus.found())
|
|
wayland_client = dependency('wayland-client')
|
|
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
|
|
|
|
-logind = dependency('libsystemd', required: false)
|
|
-if logind.found()
|
|
- add_project_arguments('-DHAVE_SYSTEMD=1', language : 'c')
|
|
+mako_deps = []
|
|
+mako_files = []
|
|
+
|
|
+if sdbus.found()
|
|
+ mako_deps += sdbus
|
|
+ add_project_arguments('-DHAVE_' + get_option('logind-provider').to_upper(), language: 'c')
|
|
else
|
|
- logind = dependency('libelogind')
|
|
- add_project_arguments('-DHAVE_ELOGIND=1', language : 'c')
|
|
+ mako_deps += dbus1
|
|
+ mako_files += [
|
|
+ 'dbus/subd-vtable.c',
|
|
+ 'dbus/subd-watch.c',
|
|
+ 'dbus/subd-sdbus.c',
|
|
+ ]
|
|
+ add_project_arguments('-DHAVE_SUBD', language: 'c')
|
|
endif
|
|
|
|
subdir('protocol')
|
|
|
|
+mako_deps += [
|
|
+ cairo,
|
|
+ client_protos,
|
|
+ sdbus,
|
|
+ pango,
|
|
+ pangocairo,
|
|
+ wayland_client,
|
|
+]
|
|
+
|
|
+mako_files += [
|
|
+ 'config.c',
|
|
+ 'dbus/dbus.c',
|
|
+ 'dbus/mako.c',
|
|
+ 'dbus/xdg.c',
|
|
+ 'event-loop.c',
|
|
+ 'main.c',
|
|
+ 'notification.c',
|
|
+ 'pool-buffer.c',
|
|
+ 'render.c',
|
|
+ 'wayland.c',
|
|
+ 'criteria.c',
|
|
+ 'types.c',
|
|
+]
|
|
+
|
|
+# epoll is a separate library in FreeBSD
|
|
+if host_machine.system() == 'freebsd'
|
|
+ mako_deps += dependency('epoll-shim')
|
|
+endif
|
|
+
|
|
executable(
|
|
'mako',
|
|
- files([
|
|
- 'config.c',
|
|
- 'event-loop.c',
|
|
- 'dbus/dbus.c',
|
|
- 'dbus/mako.c',
|
|
- 'dbus/xdg.c',
|
|
- 'main.c',
|
|
- 'notification.c',
|
|
- 'pool-buffer.c',
|
|
- 'render.c',
|
|
- 'wayland.c',
|
|
- 'criteria.c',
|
|
- 'types.c',
|
|
- ]),
|
|
- dependencies: [
|
|
- cairo,
|
|
- client_protos,
|
|
- logind,
|
|
- pango,
|
|
- pangocairo,
|
|
- wayland_client,
|
|
- ],
|
|
+ files(mako_files),
|
|
+ dependencies: mako_deps,
|
|
include_directories: [mako_inc],
|
|
install: true,
|
|
)
|
|
diff --git a/meson_options.txt b/meson_options.txt
|
|
new file mode 100644
|
|
index 0000000..6a43a8c
|
|
--- /dev/null
|
|
+++ b/meson_options.txt
|
|
@@ -0,0 +1,2 @@
|
|
+option('sdbus', type: 'feature', value: 'auto', description: 'Use sd-bus library')
|
|
+option('sdbus-provider', type: 'combo', choices: ['systemd', 'elogind'], value: 'systemd', description: 'Provider of sd-bus support library')
|
|
|
|
From 937a6bcf027391e4230588cc15d7109d85c05b54 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 26 Oct 2018 17:18:01 +0200
|
|
Subject: [PATCH 04/17] Fix some minor compile errors in event-loop.c
|
|
|
|
---
|
|
event-loop.c | 8 ++++----
|
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/event-loop.c b/event-loop.c
|
|
index 4b6c02e..f873ea1 100644
|
|
--- a/event-loop.c
|
|
+++ b/event-loop.c
|
|
@@ -3,6 +3,7 @@
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
+#include <string.h>
|
|
#include <sys/timerfd.h>
|
|
#include <signal.h>
|
|
#include <sys/signalfd.h>
|
|
@@ -76,7 +77,7 @@ bool init_event_loop(struct mako_event_loop *loop, sd_bus *bus,
|
|
struct pollfd pollfds[MAKO_EVENT_COUNT];
|
|
|
|
pollfds[MAKO_EVENT_SIGNAL] = (struct pollfd){
|
|
- .fd = loop->sfd;
|
|
+ .fd = loop->sfd,
|
|
.events = POLLIN,
|
|
};
|
|
|
|
@@ -92,15 +93,14 @@ bool init_event_loop(struct mako_event_loop *loop, sd_bus *bus,
|
|
|
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
- loop->watches = subd_init_watches(connection, pollfds, MAKO_EVENT_COUNT,
|
|
- &error);
|
|
+ loop->watches = subd_init_watches(bus, pollfds, MAKO_EVENT_COUNT, &error);
|
|
if (loop->watches == NULL) {
|
|
fprintf(stderr, "failed to initialize loop: %s\n", error.message);
|
|
return false;
|
|
}
|
|
|
|
loop->fds = loop->watches->fds;
|
|
- loop->bus = connection;
|
|
+ loop->bus = bus;
|
|
loop->display = display;
|
|
wl_list_init(&loop->timers);
|
|
|
|
|
|
From 70375e0d9103a3d6636b92ebfcb8c8d85a1473e1 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 26 Oct 2018 18:26:50 +0200
|
|
Subject: [PATCH 05/17] Fix POSIX feature test macros
|
|
|
|
This commit applies fixes for the following:
|
|
pool-buffer.c: mkstemp is in POSIX.1-2008, thus requires _POSIX_C_SOURCE
|
|
to be 200809L or higher, and _X_OPEN_SOURCE 500 does not provide that.
|
|
event-loop.c: TFD_CLOEXEC is defined as O_CLOEXEC, which also appeared
|
|
in POSIX.1-2008, thus _POSIX_C_SOURCE 199309L is not enough.
|
|
---
|
|
event-loop.c | 2 +-
|
|
pool-buffer.c | 2 +-
|
|
2 files changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/event-loop.c b/event-loop.c
|
|
index f873ea1..11f49b7 100644
|
|
--- a/event-loop.c
|
|
+++ b/event-loop.c
|
|
@@ -1,4 +1,4 @@
|
|
-#define _POSIX_C_SOURCE 199309L
|
|
+#define _POSIX_C_SOURCE 200809L
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
diff --git a/pool-buffer.c b/pool-buffer.c
|
|
index d405900..45a8282 100644
|
|
--- a/pool-buffer.c
|
|
+++ b/pool-buffer.c
|
|
@@ -1,4 +1,4 @@
|
|
-#define _XOPEN_SOURCE 500
|
|
+#define _POSIX_C_SOURCE 200809L
|
|
#include <cairo/cairo.h>
|
|
#include <fcntl.h>
|
|
#include <pango/pangocairo.h>
|
|
|
|
From dcef8379be34a2cf3ab7770f58ce6444be1a2489 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 26 Oct 2018 18:31:26 +0200
|
|
Subject: [PATCH 06/17] Add a makoctl version that uses dbus-send
|
|
|
|
busctl is part of sd-bus, so we don't have it when we are using subd.
|
|
---
|
|
makoctl.libdbus | 52 +++++++++++++++++++++++++++++++++++++++++++++++++
|
|
meson.build | 7 +++++--
|
|
2 files changed, 57 insertions(+), 2 deletions(-)
|
|
create mode 100755 makoctl.libdbus
|
|
|
|
diff --git a/makoctl.libdbus b/makoctl.libdbus
|
|
new file mode 100755
|
|
index 0000000..3d92d24
|
|
--- /dev/null
|
|
+++ b/makoctl.libdbus
|
|
@@ -0,0 +1,52 @@
|
|
+#!/bin/sh
|
|
+
|
|
+set -e
|
|
+
|
|
+usage() {
|
|
+ echo "Usage: makoctl <command> [options...]"
|
|
+ echo ""
|
|
+ echo "Commands:"
|
|
+ echo " dismiss [-a|--all] Dismiss the last or all notifications"
|
|
+ echo " invoke [action] Invoke an action on the last notification"
|
|
+ echo " reload Reload the configuration file"
|
|
+ echo " help Show this help"
|
|
+}
|
|
+
|
|
+call() {
|
|
+ dbus-send --session --dest=org.freedesktop.Notifications /fr/emersion/Mako \
|
|
+ fr.emersion.Mako."$@"
|
|
+}
|
|
+
|
|
+case "$1" in
|
|
+"dismiss")
|
|
+ case "$2" in
|
|
+ "-a"|"--all")
|
|
+ call DismissAllNotifications
|
|
+ ;;
|
|
+ "")
|
|
+ call DismissLastNotification
|
|
+ ;;
|
|
+ *)
|
|
+ echo "makoctl: unrecognized option '$2'"
|
|
+ exit 1
|
|
+ ;;
|
|
+ esac
|
|
+ ;;
|
|
+"invoke")
|
|
+ action="$2"
|
|
+ if [ -z "$action" ] ; then
|
|
+ action="default"
|
|
+ fi
|
|
+ call InvokeAction "s" "$action"
|
|
+ ;;
|
|
+"reload")
|
|
+ call Reload
|
|
+ ;;
|
|
+"help"|"--help"|"-h")
|
|
+ usage
|
|
+ ;;
|
|
+*)
|
|
+ echo "makoctl: unrecognized command '$1'"
|
|
+ exit 1
|
|
+ ;;
|
|
+esac
|
|
diff --git a/meson.build b/meson.build
|
|
index a92dbc7..5ccbea2 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -3,7 +3,7 @@ project(
|
|
'c',
|
|
version: '1.1.0',
|
|
license: 'MIT',
|
|
- meson_version: '>=0.43.0',
|
|
+ meson_version: '>=0.47.0',
|
|
default_options: [
|
|
'c_std=c11',
|
|
'warning_level=2',
|
|
@@ -79,8 +79,11 @@ executable(
|
|
install: true,
|
|
)
|
|
|
|
+makoctl = sdbus.found() ? 'makoctl' : 'makoctl.libdbus'
|
|
+
|
|
install_data(
|
|
- 'makoctl',
|
|
+ makoctl,
|
|
+ rename: 'makoctl',
|
|
install_dir: get_option('bindir'),
|
|
install_mode: 'rwxr-xr-x',
|
|
)
|
|
|
|
From 8435daa0f9f9e7d12103a6710d76bb5b9ddc7dbf Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Sun, 28 Oct 2018 19:46:43 +0100
|
|
Subject: [PATCH 07/17] Avoid sending a non-set DBusError as reply
|
|
|
|
---
|
|
dbus/subd-vtable.c | 11 ++++++-----
|
|
1 file changed, 6 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/dbus/subd-vtable.c b/dbus/subd-vtable.c
|
|
index 91b7c0e..6eab057 100644
|
|
--- a/dbus/subd-vtable.c
|
|
+++ b/dbus/subd-vtable.c
|
|
@@ -189,11 +189,12 @@ static bool call_method(const struct subd_member *member, DBusConnection *conn,
|
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (member->m.handler(message, userdata, &error) < 0) {
|
|
- //XXX: handle error == NULL
|
|
- DBusMessage *error_message =
|
|
- dbus_message_new_error(msg, error.name, error.message);
|
|
- dbus_connection_send(conn, error_message, 0);
|
|
- dbus_error_free(&error);
|
|
+ if (dbus_error_is_set(&error)) {
|
|
+ DBusMessage *error_message =
|
|
+ dbus_message_new_error(msg, error.name, error.message);
|
|
+ dbus_connection_send(conn, error_message, 0);
|
|
+ dbus_error_free(&error);
|
|
+ }
|
|
return false;
|
|
}
|
|
return true;
|
|
|
|
From c186e763881d7a8fffba3f1b5abdef89b8f4986e Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Mon, 29 Oct 2018 09:52:58 +0100
|
|
Subject: [PATCH 08/17] Free wl_list on error and message unref
|
|
|
|
---
|
|
dbus/subd-sdbus.c | 17 ++++++++++++-----
|
|
1 file changed, 12 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/dbus/subd-sdbus.c b/dbus/subd-sdbus.c
|
|
index eccdc14..3df1a0f 100644
|
|
--- a/dbus/subd-sdbus.c
|
|
+++ b/dbus/subd-sdbus.c
|
|
@@ -41,6 +41,8 @@ void sd_bus_error_set_const(sd_bus_error *err, const char *name, const char *msg
|
|
int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newmsg) {
|
|
sd_bus_message *new_message = NULL;
|
|
DBusMessage *message = NULL;
|
|
+ struct msg_iter *iter = NULL;
|
|
+
|
|
// Allocate a new "method return" DBusMessage
|
|
if ((message = dbus_message_new_method_return(msg->message)) == NULL) {
|
|
goto error;
|
|
@@ -58,7 +60,7 @@ int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newms
|
|
new_message->message = message;
|
|
new_message->ref_count = 1;
|
|
|
|
- //Also initialize the sd_bus_message's iterator stack, ...
|
|
+ //Also initialize the sd_bus_message's iterator stack, ...
|
|
new_message->iters = malloc(sizeof(struct wl_list));
|
|
if (new_message->iters == NULL) {
|
|
goto error;
|
|
@@ -66,7 +68,7 @@ int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newms
|
|
wl_list_init(new_message->iters);
|
|
|
|
// ... and push a new append iterator to it.
|
|
- struct msg_iter *iter = malloc(sizeof(struct msg_iter));
|
|
+ iter = malloc(sizeof(struct msg_iter));
|
|
if (iter == NULL) {
|
|
goto error;
|
|
}
|
|
@@ -78,7 +80,8 @@ int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newms
|
|
return 0;
|
|
|
|
error:
|
|
- //XXX list_destroy(new_message->iters);
|
|
+ free(iter);
|
|
+ free(new_message->iters);
|
|
free(new_message);
|
|
dbus_message_unref(message);
|
|
*newmsg = NULL;
|
|
@@ -152,8 +155,12 @@ int sd_bus_message_append(sd_bus_message *msg, const char *signature, ...) {
|
|
|
|
void sd_bus_message_unref(sd_bus_message *msg) {
|
|
dbus_message_unref(msg->message);
|
|
- if (msg->ref_count == 0) {
|
|
- //XXX list_destroy(msg->iters);
|
|
+ if (--msg->ref_count == 0) {
|
|
+ struct msg_iter *iter, *itertmp = NULL;
|
|
+ wl_list_for_each_safe(iter, itertmp, msg->iters, link) {
|
|
+ free(iter);
|
|
+ }
|
|
+ free(msg->iters);
|
|
free(msg);
|
|
}
|
|
}
|
|
|
|
From 485e668644033a0d2d5c56d0ddeeb3da46c197a4 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Mon, 29 Oct 2018 09:59:47 +0100
|
|
Subject: [PATCH 09/17] Remove TODO about dbus_watch_handle error handling
|
|
|
|
A call to dbus_watch_handle fails if there is not enough memory. In such
|
|
case, the "application may spin in a busy loop on the file descriptor
|
|
until memory becomes available, but nothing more catastrophic should
|
|
happen" (from libdbus documentation). I think this is better, than
|
|
potentially blocking the handling of other fd events with a sleep.
|
|
---
|
|
dbus/subd-watch.c | 3 +--
|
|
1 file changed, 1 insertion(+), 2 deletions(-)
|
|
|
|
diff --git a/dbus/subd-watch.c b/dbus/subd-watch.c
|
|
index ef913e7..5b6190e 100644
|
|
--- a/dbus/subd-watch.c
|
|
+++ b/dbus/subd-watch.c
|
|
@@ -168,9 +168,8 @@ void subd_process_watches(DBusConnection *conn, struct subd_watches *watches) {
|
|
flags |= DBUS_WATCH_ERROR;
|
|
}
|
|
|
|
- //TODO: Error handling. Not sure, what is the right move here. Log
|
|
- // and ignore? Make them fatal?
|
|
dbus_watch_handle(watch, flags);
|
|
+
|
|
while (dbus_connection_dispatch(conn) ==
|
|
DBUS_DISPATCH_DATA_REMAINS);
|
|
}
|
|
|
|
From 0a371a4802615d718edef2af540d636925da9604 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Mon, 29 Oct 2018 14:01:48 +0100
|
|
Subject: [PATCH 10/17] Refactor sd_bus_add_object_vtable
|
|
|
|
This function was too big, and also didn't do all the necessary resource
|
|
deallocation in case of errors.
|
|
---
|
|
dbus/subd-vtable.c | 165 ++++++++++++++++++++++++-------------------
|
|
include/subd-sdbus.h | 2 +-
|
|
2 files changed, 94 insertions(+), 73 deletions(-)
|
|
|
|
diff --git a/dbus/subd-vtable.c b/dbus/subd-vtable.c
|
|
index 6eab057..c2aed8d 100644
|
|
--- a/dbus/subd-vtable.c
|
|
+++ b/dbus/subd-vtable.c
|
|
@@ -236,10 +236,75 @@ static const DBusObjectPathVTable dbus_vtable = {
|
|
.unregister_function = NULL,
|
|
};
|
|
|
|
+static struct path *register_new_path(sd_bus * bus, const char *path_name,
|
|
+ void *userdata) {
|
|
+ struct wl_list *interfaces = NULL;
|
|
+ struct interface *new_interface = NULL;
|
|
+ struct path *new_path = NULL;
|
|
+ struct vtable_userdata *data = NULL;
|
|
+
|
|
+ // We create an interface list, and append Introspectable to it. We want
|
|
+ // every path to implement org.freedesktop.DBus.Introspectable.
|
|
+ // TODO: Also implement the following:
|
|
+ // - org.freedesktop.DBus.Peer
|
|
+ // - org.freedesktop.DBus.Properties
|
|
+ interfaces = malloc(sizeof(struct wl_list));
|
|
+ if (interfaces == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+ wl_list_init(interfaces);
|
|
+
|
|
+ new_interface = malloc(sizeof(struct interface));
|
|
+ if (new_interface == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ new_interface->name = strdup("org.freedesktop.DBus.Introspectable");
|
|
+ new_interface->members = introspectable_members;
|
|
+ wl_list_insert(interfaces, &new_interface->link);
|
|
+
|
|
+ // Create the path with the new interface list
|
|
+ new_path = malloc(sizeof(struct path));
|
|
+ if (new_path == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ new_path->path = strdup(path_name);
|
|
+ new_path->interfaces = interfaces;
|
|
+ new_path->introspection_data = NULL; // This will be set later.
|
|
+
|
|
+ // ... and also register it.
|
|
+ // We merge userdata with the interfaces list in a struct
|
|
+ // vtable_userdata here, so vtable_dispatch will know what interfaces to
|
|
+ // traverse, and what userdata to pass to the actual handler functions.
|
|
+ data = malloc(sizeof(struct vtable_userdata));
|
|
+ if (data == NULL) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ data->interfaces = interfaces;
|
|
+ data->userdata = userdata;
|
|
+ if (!dbus_connection_try_register_object_path(bus, path_name, &dbus_vtable,
|
|
+ data, NULL)) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ // Append the path to the list of paths
|
|
+ wl_list_insert(paths, &new_path->link);
|
|
+
|
|
+ return new_path;
|
|
+
|
|
+error:
|
|
+ free(data);
|
|
+ free(new_path);
|
|
+ free(new_interface);
|
|
+ free(interfaces);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot,
|
|
- const char *path_name, const char *interface,
|
|
+ const char *path_name, const char *interface_name,
|
|
const sd_bus_vtable *vtable, void *userdata) {
|
|
- int ret = 0;
|
|
|
|
if (paths == NULL) {
|
|
paths = malloc(sizeof(struct path));
|
|
@@ -249,90 +314,46 @@ int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot,
|
|
wl_list_init(paths);
|
|
}
|
|
|
|
- // See if this path is already registered. If it is, it must have at least
|
|
- // one interface, so get a pointer to the interfaces list.
|
|
- struct wl_list *interfaces = NULL;
|
|
+ // See if this path is already registered, ...
|
|
struct path *p, *path = NULL;
|
|
wl_list_for_each(p, paths, link) {
|
|
if (strcmp(path_name, p->path) == 0) {
|
|
path = p;
|
|
- interfaces = p->interfaces;
|
|
break;
|
|
}
|
|
}
|
|
|
|
- if (interfaces == NULL) {
|
|
- // Path was not registered before, so first we create an interface list,
|
|
- // and append Introspectable to it. We want every path to implement
|
|
- // org.freedesktop.DBus.Introspectable.
|
|
- // TODO: Also implement the following:
|
|
- // - org.freedesktop.DBus.Peer
|
|
- // - org.freedesktop.DBus.Properties
|
|
- interfaces = malloc(sizeof(struct wl_list));
|
|
- if (interfaces == NULL) {
|
|
- ret = -ENOMEM;
|
|
- goto finish;
|
|
- }
|
|
- wl_list_init(interfaces);
|
|
- struct interface *new_interface = malloc(sizeof(struct interface));
|
|
- if (interface == NULL) {
|
|
- ret = -ENOMEM;
|
|
- goto finish;
|
|
- }
|
|
- new_interface->name = strdup("org.freedesktop.DBus.Introspectable");
|
|
- new_interface->members = introspectable_members;
|
|
- wl_list_insert(interfaces, &new_interface->link);
|
|
-
|
|
- // Create the path with the new interface list
|
|
- struct path *new_path = malloc(sizeof(struct path));
|
|
- if (new_path == NULL) {
|
|
- ret = -ENOMEM;
|
|
- goto finish;
|
|
- }
|
|
- new_path->path = strdup(path_name);
|
|
- new_path->interfaces = interfaces;
|
|
- new_path->introspection_data = NULL; // This will be set later.
|
|
- path = new_path;
|
|
-
|
|
- // ... and also register it.
|
|
- // We merge userdata with the interfaces list in a struct
|
|
- // vtable_userdata here, so vtable_dispatch will know what interfaces to
|
|
- // traverse, and what userdata to pass to the actual handler functions.
|
|
- struct vtable_userdata *data = malloc(sizeof(struct vtable_userdata));
|
|
- if (data == NULL) {
|
|
- free(new_path);
|
|
- ret = -ENOMEM;
|
|
- goto finish;
|
|
- }
|
|
- data->interfaces = interfaces;
|
|
- data->userdata = userdata;
|
|
- if (!dbus_connection_try_register_object_path(bus, path_name,
|
|
- &dbus_vtable, data, NULL)) {
|
|
- free(new_path);
|
|
- ret = -ENXIO;
|
|
- goto finish;
|
|
- }
|
|
+ // ... and if it is not, register it.
|
|
+ if (path == NULL &&
|
|
+ (path = register_new_path(bus, path_name, userdata)) == NULL) {
|
|
+ return -ENOMEM;
|
|
}
|
|
|
|
- //TODO: Decide what to do if interface is already registered. Replace
|
|
- //memeber list? Append new members to list? Throw an error?
|
|
-
|
|
- // Append the new interface to the path's interface list.
|
|
- struct interface *new_interface = malloc(sizeof(struct interface));
|
|
- if (new_interface == NULL) {
|
|
- ret = -ENOMEM;
|
|
- goto finish;
|
|
+ // See if the path already has an interface with this name, ...
|
|
+ struct interface *i, *interface = NULL;
|
|
+ wl_list_for_each(i, path->interfaces, link) {
|
|
+ if (strcmp(i->name, interface_name) == 0) {
|
|
+ interface = i;
|
|
+ break;
|
|
+ }
|
|
}
|
|
- new_interface->name = strdup(interface);
|
|
- new_interface->members = vtable;
|
|
- wl_list_insert(interfaces, &new_interface->link);
|
|
|
|
- // Append the path to the list of paths
|
|
- wl_list_insert(paths, &path->link);
|
|
+ // ... and create it, if not. If it does, replace the vtable for the
|
|
+ // existing interface.
|
|
+ if (interface == NULL) {
|
|
+ interface = malloc(sizeof(struct interface));
|
|
+ if (interface == NULL) {
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ interface->name = strdup(interface_name);
|
|
+ interface->members = vtable;
|
|
+ wl_list_insert(path->interfaces, &interface->link);
|
|
+ } else {
|
|
+ interface->members = vtable;
|
|
+ }
|
|
|
|
// (Re)generate introspection XML for this path.
|
|
generate_introspection_data(path);
|
|
|
|
-finish:
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
diff --git a/include/subd-sdbus.h b/include/subd-sdbus.h
|
|
index 8d77600..e7d177d 100644
|
|
--- a/include/subd-sdbus.h
|
|
+++ b/include/subd-sdbus.h
|
|
@@ -137,6 +137,6 @@ int sd_bus_reply_method_return(sd_bus_message *msg, const char *signature, ...);
|
|
int sd_bus_send(sd_bus *bus, sd_bus_message *msg, dbus_uint32_t *cookie);
|
|
|
|
int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path_name,
|
|
- const char *interface, const sd_bus_vtable *vtable, void *data);
|
|
+ const char *interface_name, const sd_bus_vtable *vtable, void *userdata);
|
|
|
|
#endif
|
|
|
|
From 6e7c60cbbad548a21bec96b3b34d6c074ab42a3c Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Mon, 29 Oct 2018 14:40:36 +0100
|
|
Subject: [PATCH 11/17] Add feature test macros where necessary
|
|
|
|
strdup requires _POSIX_C_SOURCE 200112L
|
|
open_memstream requires _POSIX_C_SOURCE 200809L
|
|
---
|
|
dbus/subd-sdbus.c | 1 +
|
|
dbus/subd-vtable.c | 1 +
|
|
2 files changed, 2 insertions(+)
|
|
|
|
diff --git a/dbus/subd-sdbus.c b/dbus/subd-sdbus.c
|
|
index 3df1a0f..a6cb0a5 100644
|
|
--- a/dbus/subd-sdbus.c
|
|
+++ b/dbus/subd-sdbus.c
|
|
@@ -1,3 +1,4 @@
|
|
+#define _POSIX_C_SOURCE 200112L
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
diff --git a/dbus/subd-vtable.c b/dbus/subd-vtable.c
|
|
index c2aed8d..684f26d 100644
|
|
--- a/dbus/subd-vtable.c
|
|
+++ b/dbus/subd-vtable.c
|
|
@@ -1,3 +1,4 @@
|
|
+#define _POSIX_C_SOURCE 200809L
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
From fa8ba987e3fcb8c584f3342ebd0ae5b3b5c61998 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Mon, 29 Oct 2018 17:34:30 +0100
|
|
Subject: [PATCH 12/17] Fix actions
|
|
|
|
Actions were not working, because I misunderstood the return values of
|
|
the sd_bus_message_read function. The makoctl.libdbus script also
|
|
needed a fix because dbus-send's syntax for message arguments differs
|
|
from busctl's.
|
|
---
|
|
dbus/subd-sdbus.c | 2 +-
|
|
makoctl.libdbus | 2 +-
|
|
2 files changed, 2 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/dbus/subd-sdbus.c b/dbus/subd-sdbus.c
|
|
index a6cb0a5..7282a69 100644
|
|
--- a/dbus/subd-sdbus.c
|
|
+++ b/dbus/subd-sdbus.c
|
|
@@ -213,7 +213,7 @@ int sd_bus_message_readv(sd_bus_message *msg, const char *signature, va_list ap)
|
|
dbus_message_iter_next(msg->iter);
|
|
} while (dbus_signature_iter_next(&iter));
|
|
|
|
- return dbus_message_iter_has_next(msg->iter);
|
|
+ return 1;
|
|
}
|
|
|
|
int sd_bus_message_read(sd_bus_message *msg, const char *signature, ...) {
|
|
diff --git a/makoctl.libdbus b/makoctl.libdbus
|
|
index 3d92d24..6c287d0 100755
|
|
--- a/makoctl.libdbus
|
|
+++ b/makoctl.libdbus
|
|
@@ -37,7 +37,7 @@ case "$1" in
|
|
if [ -z "$action" ] ; then
|
|
action="default"
|
|
fi
|
|
- call InvokeAction "s" "$action"
|
|
+ call InvokeAction "string:$action"
|
|
;;
|
|
"reload")
|
|
call Reload
|
|
|
|
From 6317f150471fcf9dfe77ff93e4683246d37ee0c3 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Tue, 30 Oct 2018 17:49:47 +0100
|
|
Subject: [PATCH 13/17] Change iters field from wl_list* to wl_list
|
|
|
|
There's no need to dynamically allocate the list that represents the
|
|
message's iterator stack in sd_bus_message.
|
|
+bonus: Fixed two typos.
|
|
---
|
|
dbus/subd-sdbus.c | 24 +++++++++---------------
|
|
dbus/subd-vtable.c | 10 +++-------
|
|
include/subd-sdbus.h | 4 ++--
|
|
3 files changed, 14 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/dbus/subd-sdbus.c b/dbus/subd-sdbus.c
|
|
index 7282a69..012f3e3 100644
|
|
--- a/dbus/subd-sdbus.c
|
|
+++ b/dbus/subd-sdbus.c
|
|
@@ -62,11 +62,7 @@ int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newms
|
|
new_message->ref_count = 1;
|
|
|
|
//Also initialize the sd_bus_message's iterator stack, ...
|
|
- new_message->iters = malloc(sizeof(struct wl_list));
|
|
- if (new_message->iters == NULL) {
|
|
- goto error;
|
|
- }
|
|
- wl_list_init(new_message->iters);
|
|
+ wl_list_init(&new_message->iters);
|
|
|
|
// ... and push a new append iterator to it.
|
|
iter = malloc(sizeof(struct msg_iter));
|
|
@@ -74,7 +70,7 @@ int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newms
|
|
goto error;
|
|
}
|
|
dbus_message_iter_init_append(new_message->message, &iter->iter);
|
|
- wl_list_insert(new_message->iters, &iter->link);
|
|
+ wl_list_insert(&new_message->iters, &iter->link);
|
|
new_message->iter = &iter->iter;
|
|
|
|
*newmsg = new_message;
|
|
@@ -82,7 +78,6 @@ int sd_bus_message_new_method_return(sd_bus_message *msg, sd_bus_message **newms
|
|
|
|
error:
|
|
free(iter);
|
|
- free(new_message->iters);
|
|
free(new_message);
|
|
dbus_message_unref(message);
|
|
*newmsg = NULL;
|
|
@@ -99,7 +94,7 @@ int sd_bus_message_open_container(sd_bus_message *msg, char type,
|
|
if (!dbus_message_iter_open_container(msg->iter, type, signature, &sub->iter)) {
|
|
goto error;
|
|
}
|
|
- wl_list_insert(msg->iters, &sub->link);
|
|
+ wl_list_insert(&msg->iters, &sub->link);
|
|
msg->iter = &sub->iter;
|
|
|
|
return 0;
|
|
@@ -111,11 +106,11 @@ int sd_bus_message_open_container(sd_bus_message *msg, char type,
|
|
|
|
int sd_bus_message_close_container(sd_bus_message *msg) {
|
|
// Remove the iterator we want to close from from the iterator stack
|
|
- struct msg_iter *iter = wl_container_of(msg->iters->next, iter, link);
|
|
+ struct msg_iter *iter = wl_container_of(msg->iters.next, iter, link);
|
|
wl_list_remove(&iter->link);
|
|
|
|
// Set msg's current iterator to the top of the iterator stack.
|
|
- struct msg_iter *new_head = wl_container_of(msg->iters->next, iter, link);
|
|
+ struct msg_iter *new_head = wl_container_of(msg->iters.next, iter, link);
|
|
msg->iter = &new_head->iter;
|
|
|
|
// Close the container.
|
|
@@ -158,10 +153,9 @@ void sd_bus_message_unref(sd_bus_message *msg) {
|
|
dbus_message_unref(msg->message);
|
|
if (--msg->ref_count == 0) {
|
|
struct msg_iter *iter, *itertmp = NULL;
|
|
- wl_list_for_each_safe(iter, itertmp, msg->iters, link) {
|
|
+ wl_list_for_each_safe(iter, itertmp, &msg->iters, link) {
|
|
free(iter);
|
|
}
|
|
- free(msg->iters);
|
|
free(msg);
|
|
}
|
|
}
|
|
@@ -292,7 +286,7 @@ int sd_bus_message_enter_container(sd_bus_message *msg, char type,
|
|
}
|
|
|
|
dbus_message_iter_recurse(msg->iter, &sub_iter->iter);
|
|
- wl_list_insert(msg->iters, &sub_iter->link);
|
|
+ wl_list_insert(&msg->iters, &sub_iter->link);
|
|
msg->iter = &sub_iter->iter;
|
|
|
|
return dbus_message_iter_has_next(&sub_iter->iter);
|
|
@@ -300,12 +294,12 @@ int sd_bus_message_enter_container(sd_bus_message *msg, char type,
|
|
|
|
int sd_bus_message_exit_container(sd_bus_message *msg) {
|
|
// Remove the iterator we want to exit from from the iterator stack
|
|
- struct msg_iter *iter = wl_container_of(msg->iters->next, iter, link);
|
|
+ struct msg_iter *iter = wl_container_of(msg->iters.next, iter, link);
|
|
wl_list_remove(&iter->link);
|
|
|
|
// Set msg's current iterator to the top of the iterator stack, and use
|
|
// dbus_message_iter_next to "step over" the iterator we are exiting.
|
|
- iter = wl_container_of(msg->iters->next, iter, link);
|
|
+ iter = wl_container_of(msg->iters.next, iter, link);
|
|
msg->iter = &iter->iter;
|
|
dbus_message_iter_next(msg->iter);
|
|
|
|
diff --git a/dbus/subd-vtable.c b/dbus/subd-vtable.c
|
|
index 684f26d..f2b6d5a 100644
|
|
--- a/dbus/subd-vtable.c
|
|
+++ b/dbus/subd-vtable.c
|
|
@@ -173,18 +173,14 @@ static bool call_method(const struct subd_member *member, DBusConnection *conn,
|
|
message->bus = conn;
|
|
message->message = msg;
|
|
message->ref_count = 1;
|
|
- message->iters = malloc(sizeof(struct wl_list));
|
|
- if (message->iters == NULL) {
|
|
- return false;
|
|
- }
|
|
- wl_list_init(message->iters);
|
|
+ wl_list_init(&message->iters);
|
|
|
|
struct msg_iter *iter = malloc(sizeof(struct msg_iter));
|
|
if (iter == NULL) {
|
|
return false;
|
|
}
|
|
dbus_message_iter_init(message->message, &iter->iter);
|
|
- wl_list_insert(message->iters, &iter->link);
|
|
+ wl_list_insert(&message->iters, &iter->link);
|
|
message->iter = &iter->iter;
|
|
|
|
DBusError error;
|
|
@@ -325,7 +321,7 @@ int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot,
|
|
}
|
|
|
|
// ... and if it is not, register it.
|
|
- if (path == NULL &&
|
|
+ if (path == NULL &&
|
|
(path = register_new_path(bus, path_name, userdata)) == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
diff --git a/include/subd-sdbus.h b/include/subd-sdbus.h
|
|
index e7d177d..b676d61 100644
|
|
--- a/include/subd-sdbus.h
|
|
+++ b/include/subd-sdbus.h
|
|
@@ -18,7 +18,7 @@ typedef struct DBusError sd_bus_error;
|
|
typedef struct subd_member sd_bus_vtable;
|
|
|
|
/**
|
|
- * his is not used, but typedef-d to preserve sd-bus function signatures.
|
|
+ * This is not used, but typedef-d to preserve sd-bus function signatures.
|
|
*/
|
|
typedef int sd_bus_slot;
|
|
|
|
@@ -39,7 +39,7 @@ typedef struct sd_bus_message {
|
|
sd_bus *bus;
|
|
DBusMessage *message;
|
|
DBusMessageIter *iter;
|
|
- struct wl_list *iters;
|
|
+ struct wl_list iters;
|
|
int ref_count;
|
|
} sd_bus_message;
|
|
|
|
|
|
From 38f4b397865d76a696126f09a5d992db96e7acf5 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Wed, 31 Oct 2018 06:14:16 +0100
|
|
Subject: [PATCH 14/17] Fix watch storage capacity increment
|
|
|
|
The return value of successful realloc calls was ignored.
|
|
This commit also replaces malloc with calloc for the DBusWatch * and
|
|
pollfd arrays, and improves deallocation in case of errors.
|
|
---
|
|
dbus/subd-watch.c | 31 +++++++++++++++++++------------
|
|
1 file changed, 19 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/dbus/subd-watch.c b/dbus/subd-watch.c
|
|
index 5b6190e..aa85c81 100644
|
|
--- a/dbus/subd-watch.c
|
|
+++ b/dbus/subd-watch.c
|
|
@@ -16,14 +16,24 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
|
|
|
|
if (watches->length == watches->capacity) {
|
|
int c = watches->capacity + 10;
|
|
- void *t1 = realloc(watches->fds, sizeof(struct pollfd) * c);
|
|
- void *t2 = realloc(watches->watches, sizeof(DBusWatch *) * c);
|
|
- if (t1 == NULL || t2 == NULL) {
|
|
+
|
|
+ void *new_fds = realloc(watches->fds, sizeof(struct pollfd) * c);
|
|
+ if (new_fds != NULL) {
|
|
+ watches->fds = new_fds;
|
|
+ } else {
|
|
sem_post(&watches->mutex);
|
|
return FALSE;
|
|
+ }
|
|
+
|
|
+ void *new_watches = realloc(watches->watches, sizeof(DBusWatch *) * c);
|
|
+ if (new_watches != NULL) {
|
|
+ watches->watches = new_watches;
|
|
} else {
|
|
- watches->capacity = c;
|
|
+ sem_post(&watches->mutex);
|
|
+ return FALSE;
|
|
}
|
|
+
|
|
+ watches->capacity = c;
|
|
}
|
|
|
|
short mask = 0;
|
|
@@ -89,8 +99,8 @@ struct subd_watches *subd_init_watches(struct DBusConnection *connection,
|
|
|
|
watches->capacity = 10 + size;
|
|
watches->length = size;
|
|
- watches->fds = malloc(watches->capacity * sizeof(struct pollfd));
|
|
- watches->watches = malloc(watches->capacity * sizeof(DBusWatch*));
|
|
+ watches->fds = calloc(watches->capacity, sizeof(struct pollfd));
|
|
+ watches->watches = calloc(watches->capacity, sizeof(DBusWatch*));
|
|
if (watches->fds == NULL || watches->watches == NULL) {
|
|
error_code = DBUS_ERROR_NO_MEMORY;
|
|
goto error;
|
|
@@ -131,12 +141,9 @@ struct subd_watches *subd_init_watches(struct DBusConnection *connection,
|
|
|
|
error:
|
|
if (watches != NULL) {
|
|
- if (watches->fds != NULL) {
|
|
- free(watches->fds);
|
|
- }
|
|
- if (watches->watches != NULL) {
|
|
- free(watches->watches);
|
|
- }
|
|
+ free(watches->fds);
|
|
+ free(watches->watches);
|
|
+ free(watches);
|
|
}
|
|
dbus_set_error(error, error_code, NULL);
|
|
return NULL;
|
|
|
|
From 0c5c364ca98854a4b30b83acade1be6a90adafcc Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Wed, 31 Oct 2018 16:02:40 +0100
|
|
Subject: [PATCH 15/17] Change subd_watches to subd_watch_store
|
|
|
|
I use plurals in variable names to imply an array, or some kind of list,
|
|
and this is a struct (that contains two arrays, but still). Also things
|
|
like watches->watches could be confusing.
|
|
---
|
|
dbus/subd-watch.c | 104 +++++++++++++++++++++----------------------
|
|
event-loop.c | 10 ++---
|
|
include/event-loop.h | 2 +-
|
|
include/subd.h | 8 ++--
|
|
4 files changed, 62 insertions(+), 62 deletions(-)
|
|
|
|
diff --git a/dbus/subd-watch.c b/dbus/subd-watch.c
|
|
index aa85c81..718ea78 100644
|
|
--- a/dbus/subd-watch.c
|
|
+++ b/dbus/subd-watch.c
|
|
@@ -6,34 +6,34 @@
|
|
#include "subd.h"
|
|
|
|
static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
|
|
- struct subd_watches *watches = data;
|
|
- sem_wait(&watches->mutex);
|
|
+ struct subd_watch_store *watch_store = data;
|
|
+ sem_wait(&watch_store->mutex);
|
|
|
|
if (!dbus_watch_get_enabled(watch)) {
|
|
- sem_post(&watches->mutex);
|
|
+ sem_post(&watch_store->mutex);
|
|
return TRUE;
|
|
}
|
|
|
|
- if (watches->length == watches->capacity) {
|
|
- int c = watches->capacity + 10;
|
|
+ if (watch_store->length == watch_store->capacity) {
|
|
+ int c = watch_store->capacity + 10;
|
|
|
|
- void *new_fds = realloc(watches->fds, sizeof(struct pollfd) * c);
|
|
+ void *new_fds = realloc(watch_store->fds, sizeof(struct pollfd) * c);
|
|
if (new_fds != NULL) {
|
|
- watches->fds = new_fds;
|
|
+ watch_store->fds = new_fds;
|
|
} else {
|
|
- sem_post(&watches->mutex);
|
|
+ sem_post(&watch_store->mutex);
|
|
return FALSE;
|
|
}
|
|
|
|
- void *new_watches = realloc(watches->watches, sizeof(DBusWatch *) * c);
|
|
+ void *new_watches = realloc(watch_store->watches, sizeof(DBusWatch *) * c);
|
|
if (new_watches != NULL) {
|
|
- watches->watches = new_watches;
|
|
+ watch_store->watches = new_watches;
|
|
} else {
|
|
- sem_post(&watches->mutex);
|
|
+ sem_post(&watch_store->mutex);
|
|
return FALSE;
|
|
}
|
|
|
|
- watches->capacity = c;
|
|
+ watch_store->capacity = c;
|
|
}
|
|
|
|
short mask = 0;
|
|
@@ -47,35 +47,35 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
|
|
|
|
int fd = dbus_watch_get_unix_fd(watch);
|
|
struct pollfd pollfd = {fd, mask, 0};
|
|
- int index = watches->length++;
|
|
- watches->fds[index] = pollfd;
|
|
- watches->watches[index] = watch;
|
|
+ int index = watch_store->length++;
|
|
+ watch_store->fds[index] = pollfd;
|
|
+ watch_store->watches[index] = watch;
|
|
|
|
- sem_post(&watches->mutex);
|
|
+ sem_post(&watch_store->mutex);
|
|
return TRUE;
|
|
}
|
|
|
|
static void remove_watch(DBusWatch *watch, void *data) {
|
|
- struct subd_watches *watches = data;
|
|
- sem_wait(&watches->mutex);
|
|
+ struct subd_watch_store *watch_store = data;
|
|
+ sem_wait(&watch_store->mutex);
|
|
|
|
int index = -1;
|
|
- for (int i = 0; i < watches->length; ++i) {
|
|
- if (watches->watches[i] == watch) {
|
|
+ for (int i = 0; i < watch_store->length; ++i) {
|
|
+ if (watch_store->watches[i] == watch) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index != -1) {
|
|
- --watches->length;
|
|
- memmove(&watches->fds[index], &watches->fds[index + 1],
|
|
- sizeof(struct pollfd) * watches->length - index);
|
|
- memmove(&watches->watches[index], &watches->watches[index + 1],
|
|
- sizeof(DBusWatch *) * watches->length - index);
|
|
+ --watch_store->length;
|
|
+ memmove(&watch_store->fds[index], &watch_store->fds[index + 1],
|
|
+ sizeof(struct pollfd) * watch_store->length - index);
|
|
+ memmove(&watch_store->watches[index], &watch_store->watches[index + 1],
|
|
+ sizeof(DBusWatch *) * watch_store->length - index);
|
|
}
|
|
|
|
- sem_post(&watches->mutex);
|
|
+ sem_post(&watch_store->mutex);
|
|
}
|
|
|
|
static void toggle_watch(DBusWatch *watch, void *data) {
|
|
@@ -86,22 +86,22 @@ static void toggle_watch(DBusWatch *watch, void *data) {
|
|
}
|
|
}
|
|
|
|
-struct subd_watches *subd_init_watches(struct DBusConnection *connection,
|
|
- struct pollfd *fds, int size, DBusError *error) {
|
|
+struct subd_watch_store *subd_init_watches(DBusConnection *conn,
|
|
+ struct pollfd *fds, int size, DBusError *err) {
|
|
const char *error_code = NULL;
|
|
|
|
// Initialize the watches structure.
|
|
- struct subd_watches *watches = malloc(sizeof(struct subd_watches));
|
|
- if (watches == NULL) {
|
|
+ struct subd_watch_store *watch_store = malloc(sizeof(struct subd_watch_store));
|
|
+ if (watch_store == NULL) {
|
|
error_code = DBUS_ERROR_NO_MEMORY;
|
|
goto error;
|
|
}
|
|
|
|
- watches->capacity = 10 + size;
|
|
- watches->length = size;
|
|
- watches->fds = calloc(watches->capacity, sizeof(struct pollfd));
|
|
- watches->watches = calloc(watches->capacity, sizeof(DBusWatch*));
|
|
- if (watches->fds == NULL || watches->watches == NULL) {
|
|
+ watch_store->capacity = 10 + size;
|
|
+ watch_store->length = size;
|
|
+ watch_store->fds = calloc(watch_store->capacity, sizeof(struct pollfd));
|
|
+ watch_store->watches = calloc(watch_store->capacity, sizeof(DBusWatch*));
|
|
+ if (watch_store->fds == NULL || watch_store->watches == NULL) {
|
|
error_code = DBUS_ERROR_NO_MEMORY;
|
|
goto error;
|
|
}
|
|
@@ -109,7 +109,7 @@ struct subd_watches *subd_init_watches(struct DBusConnection *connection,
|
|
// Initialize a semaphore for the watches. It is needed to prevent the add,
|
|
// remove and toggle functions accessing the watch storage while it is being
|
|
// processed by subd_process_watches.
|
|
- if (sem_init(&watches->mutex, 0, 1) == -1) {
|
|
+ if (sem_init(&watch_store->mutex, 0, 1) == -1) {
|
|
if (errno == EINVAL) {
|
|
error_code = DBUS_ERROR_INVALID_ARGS;
|
|
} else {
|
|
@@ -120,41 +120,41 @@ struct subd_watches *subd_init_watches(struct DBusConnection *connection,
|
|
|
|
// Add any non-dbus file descriptors.
|
|
for (int i = 0; i < size; ++i) {
|
|
- watches->fds[i] = (struct pollfd){
|
|
+ watch_store->fds[i] = (struct pollfd){
|
|
.fd = fds->fd,
|
|
.events = fds->events
|
|
};
|
|
- watches->watches[i] = NULL;
|
|
+ watch_store->watches[i] = NULL;
|
|
++fds;
|
|
}
|
|
|
|
// Register the add, remove, and toggle functions.
|
|
// NOTE: Can't use the free_data_function argument to automatically free
|
|
// watches when connection finalizes, because sometimes it does not work.
|
|
- if (!dbus_connection_set_watch_functions(connection, add_watch,
|
|
- remove_watch, toggle_watch, watches, NULL)) {
|
|
+ if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
|
|
+ toggle_watch, watch_store, NULL)) {
|
|
error_code = DBUS_ERROR_NO_MEMORY;
|
|
goto error;
|
|
}
|
|
|
|
- return watches;
|
|
+ return watch_store;
|
|
|
|
error:
|
|
- if (watches != NULL) {
|
|
- free(watches->fds);
|
|
- free(watches->watches);
|
|
- free(watches);
|
|
+ if (watch_store != NULL) {
|
|
+ free(watch_store->fds);
|
|
+ free(watch_store->watches);
|
|
+ free(watch_store);
|
|
}
|
|
- dbus_set_error(error, error_code, NULL);
|
|
+ dbus_set_error(err, error_code, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
-void subd_process_watches(DBusConnection *conn, struct subd_watches *watches) {
|
|
- sem_wait(&watches->mutex);
|
|
+void subd_process_watches(DBusConnection *conn, struct subd_watch_store *watch_store) {
|
|
+ sem_wait(&watch_store->mutex);
|
|
|
|
- for (int i = 0; i < watches->length; ++i) {
|
|
- struct pollfd pollfd = watches->fds[i];
|
|
- DBusWatch *watch = watches->watches[i];
|
|
+ for (int i = 0; i < watch_store->length; ++i) {
|
|
+ struct pollfd pollfd = watch_store->fds[i];
|
|
+ DBusWatch *watch = watch_store->watches[i];
|
|
|
|
if (watch == NULL || !dbus_watch_get_enabled(watch)) {
|
|
continue;
|
|
@@ -182,5 +182,5 @@ void subd_process_watches(DBusConnection *conn, struct subd_watches *watches) {
|
|
}
|
|
}
|
|
|
|
- sem_post(&watches->mutex);
|
|
+ sem_post(&watch_store->mutex);
|
|
}
|
|
diff --git a/event-loop.c b/event-loop.c
|
|
index 11f49b7..a9e2da7 100644
|
|
--- a/event-loop.c
|
|
+++ b/event-loop.c
|
|
@@ -93,13 +93,13 @@ bool init_event_loop(struct mako_event_loop *loop, sd_bus *bus,
|
|
|
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
- loop->watches = subd_init_watches(bus, pollfds, MAKO_EVENT_COUNT, &error);
|
|
- if (loop->watches == NULL) {
|
|
+ loop->watch_store = subd_init_watches(bus, pollfds, MAKO_EVENT_COUNT, &error);
|
|
+ if (loop->watch_store == NULL) {
|
|
fprintf(stderr, "failed to initialize loop: %s\n", error.message);
|
|
return false;
|
|
}
|
|
|
|
- loop->fds = loop->watches->fds;
|
|
+ loop->fds = loop->watch_store->fds;
|
|
loop->bus = bus;
|
|
loop->display = display;
|
|
wl_list_init(&loop->timers);
|
|
@@ -122,7 +122,7 @@ static int poll_event_loop(struct mako_event_loop *loop) {
|
|
#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
return poll(loop->fds, MAKO_EVENT_COUNT, -1);
|
|
#else
|
|
- return poll(loop->fds, loop->watches->length, -1);
|
|
+ return poll(loop->fds, loop->watch_store->length, -1);
|
|
#endif
|
|
}
|
|
|
|
@@ -281,7 +281,7 @@ int run_event_loop(struct mako_event_loop *loop) {
|
|
}
|
|
}
|
|
#else
|
|
- subd_process_watches(loop->bus, loop->watches);
|
|
+ subd_process_watches(loop->bus, loop->watch_store);
|
|
#endif
|
|
|
|
if (loop->fds[MAKO_EVENT_WAYLAND].revents & POLLIN) {
|
|
diff --git a/include/event-loop.h b/include/event-loop.h
|
|
index 85d05ce..1de870b 100644
|
|
--- a/include/event-loop.h
|
|
+++ b/include/event-loop.h
|
|
@@ -27,7 +27,7 @@ struct mako_event_loop {
|
|
#if defined(HAVE_SYSTEMD) || defined(HAVE_ELOGIND)
|
|
struct pollfd fds[MAKO_EVENT_COUNT];
|
|
#else
|
|
- struct subd_watches *watches;
|
|
+ struct subd_watch_store *watch_store;
|
|
struct pollfd *fds;
|
|
#endif
|
|
sd_bus *bus;
|
|
diff --git a/include/subd.h b/include/subd.h
|
|
index 33c997b..e9c1fab 100644
|
|
--- a/include/subd.h
|
|
+++ b/include/subd.h
|
|
@@ -14,7 +14,7 @@ struct pollfd;
|
|
* If you add non-watch file descriptors, make sure to set their corresponding
|
|
* watch to NULL, so that #subd_process_watches knows to skip them.
|
|
*/
|
|
-struct subd_watches {
|
|
+struct subd_watch_store {
|
|
struct pollfd *fds;
|
|
DBusWatch **watches;
|
|
int capacity;
|
|
@@ -28,14 +28,14 @@ struct subd_watches {
|
|
* remove and toggle functions that will handle automatic file descriptor
|
|
* additions/removals.
|
|
*/
|
|
-struct subd_watches *subd_init_watches(DBusConnection *conn, struct pollfd *fds,
|
|
- int size, DBusError *error);
|
|
+struct subd_watch_store *subd_init_watches(DBusConnection *conn,
|
|
+ struct pollfd *fds, int size, DBusError *err);
|
|
|
|
/**
|
|
* This function should be called from the event loop after a successful poll to
|
|
* handle the DBus watches that need to be handled (= the watches whose file
|
|
* descriptor returned an event).
|
|
*/
|
|
-void subd_process_watches(DBusConnection *conn, struct subd_watches *watches);
|
|
+void subd_process_watches(DBusConnection *conn, struct subd_watch_store *watch_store);
|
|
|
|
#endif
|
|
|
|
From 00a82df1c2b3b7a1799a35b8a213c5f5bcf23238 Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Wed, 31 Oct 2018 20:31:35 +0100
|
|
Subject: [PATCH 16/17] Increase POSIX version in subd-sdbus.c
|
|
|
|
For some reason GLibc hides strdup with 200112L despite it being part of
|
|
IEEE Std. 1003.1-2001.
|
|
---
|
|
dbus/subd-sdbus.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/dbus/subd-sdbus.c b/dbus/subd-sdbus.c
|
|
index 012f3e3..1093508 100644
|
|
--- a/dbus/subd-sdbus.c
|
|
+++ b/dbus/subd-sdbus.c
|
|
@@ -1,4 +1,4 @@
|
|
-#define _POSIX_C_SOURCE 200112L
|
|
+#define _POSIX_C_SOURCE 200809L
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
From d64815766f33072fa4bdb9f981a54c9ca0100b9b Mon Sep 17 00:00:00 2001
|
|
From: sghctoma <sghctoma@gmail.com>
|
|
Date: Fri, 2 Nov 2018 13:53:48 +0100
|
|
Subject: [PATCH 17/17] Fix Meson errors on Linux
|
|
|
|
---
|
|
meson.build | 10 +++++-----
|
|
1 file changed, 5 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/meson.build b/meson.build
|
|
index 5ccbea2..e13ffcd 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -19,8 +19,8 @@ mako_inc = include_directories('include')
|
|
cairo = dependency('cairo')
|
|
pango = dependency('pango')
|
|
pangocairo = dependency('pangocairo')
|
|
-sdbus = dependency(get_option('sdbus-provider'), required: get_option('sdbus'))
|
|
-dbus1 = dependency('dbus-1', required: not sdbus.found())
|
|
+sdbus = dependency('lib' + get_option('sdbus-provider'), required: get_option('sdbus'))
|
|
+threads = dependency('threads')
|
|
wayland_client = dependency('wayland-client')
|
|
wayland_protos = dependency('wayland-protocols', version: '>=1.14')
|
|
|
|
@@ -29,9 +29,9 @@ mako_files = []
|
|
|
|
if sdbus.found()
|
|
mako_deps += sdbus
|
|
- add_project_arguments('-DHAVE_' + get_option('logind-provider').to_upper(), language: 'c')
|
|
+ add_project_arguments('-DHAVE_' + get_option('sdbus-provider').to_upper(), language: 'c')
|
|
else
|
|
- mako_deps += dbus1
|
|
+ mako_deps += dependency('dbus-1')
|
|
mako_files += [
|
|
'dbus/subd-vtable.c',
|
|
'dbus/subd-watch.c',
|
|
@@ -45,9 +45,9 @@ subdir('protocol')
|
|
mako_deps += [
|
|
cairo,
|
|
client_protos,
|
|
- sdbus,
|
|
pango,
|
|
pangocairo,
|
|
+ threads,
|
|
wayland_client,
|
|
]
|
|
|