summaryrefslogtreecommitdiff
path: root/src/libsystemd-bus
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r--src/libsystemd-bus/bus-error.h2
-rw-r--r--src/libsystemd-bus/bus-internal.h4
-rw-r--r--src/libsystemd-bus/bus-introspect.c6
-rw-r--r--src/libsystemd-bus/bus-introspect.h2
-rw-r--r--src/libsystemd-bus/bus-message.c1
-rw-r--r--src/libsystemd-bus/bus-objects.c360
-rw-r--r--src/libsystemd-bus/bus-signature.c15
-rw-r--r--src/libsystemd-bus/bus-util.c42
-rw-r--r--src/libsystemd-bus/bus-util.h68
-rw-r--r--src/libsystemd-bus/sd-bus.c224
-rw-r--r--src/libsystemd-bus/sd-event.c32
-rw-r--r--src/libsystemd-bus/test-bus-introspect.c4
-rw-r--r--src/libsystemd-bus/test-bus-marshal.c2
13 files changed, 514 insertions, 248 deletions
diff --git a/src/libsystemd-bus/bus-error.h b/src/libsystemd-bus/bus-error.h
index 5474c8c5ec..f442e953e0 100644
--- a/src/libsystemd-bus/bus-error.h
+++ b/src/libsystemd-bus/bus-error.h
@@ -21,6 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.h>
+
#include "sd-bus.h"
bool bus_error_is_dirty(sd_bus_error *e);
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index faed183990..a1d60b1133 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -119,11 +119,12 @@ enum bus_state {
BUS_AUTHENTICATING,
BUS_HELLO,
BUS_RUNNING,
+ BUS_CLOSING,
BUS_CLOSED
};
static inline bool BUS_IS_OPEN(enum bus_state state) {
- return state > BUS_UNSET && state < BUS_CLOSED;
+ return state > BUS_UNSET && state < BUS_CLOSING;
}
enum bus_auth {
@@ -155,7 +156,6 @@ struct sd_bus {
bool anonymous_auth:1;
bool prefer_readv:1;
bool prefer_writev:1;
- bool processing:1;
bool match_callbacks_modified:1;
bool filter_callbacks_modified:1;
bool nodes_modified:1;
diff --git a/src/libsystemd-bus/bus-introspect.c b/src/libsystemd-bus/bus-introspect.c
index 9a49e431c0..4c6031729a 100644
--- a/src/libsystemd-bus/bus-introspect.c
+++ b/src/libsystemd-bus/bus-introspect.c
@@ -111,13 +111,10 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur
}
}
-int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v) {
+int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
assert(i);
- assert(interface);
assert(v);
- fprintf(i->f, " <interface name=\"%s\">\n", interface);
-
for (; v->type != _SD_BUS_VTABLE_END; v++) {
switch (v->type) {
@@ -155,7 +152,6 @@ int introspect_write_interface(struct introspect *i, const char *interface, cons
}
- fputs(" </interface>\n", i->f);
return 0;
}
diff --git a/src/libsystemd-bus/bus-introspect.h b/src/libsystemd-bus/bus-introspect.h
index 48c3885d94..0be12cffb9 100644
--- a/src/libsystemd-bus/bus-introspect.h
+++ b/src/libsystemd-bus/bus-introspect.h
@@ -36,6 +36,6 @@ struct introspect {
int introspect_begin(struct introspect *i);
int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
-int introspect_write_interface(struct introspect *i, const char *interface, const sd_bus_vtable *v);
+int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
void introspect_free(struct introspect *i);
diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c
index 4f21db56e2..666307cc6e 100644
--- a/src/libsystemd-bus/bus-message.c
+++ b/src/libsystemd-bus/bus-message.c
@@ -3294,6 +3294,7 @@ _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
return !isempty(c->signature);
}
+
static int message_read_ap(
sd_bus_message *m,
const char *types,
diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c
index 8369068bd0..a6e8b2de86 100644
--- a/src/libsystemd-bus/bus-objects.c
+++ b/src/libsystemd-bus/bus-objects.c
@@ -728,6 +728,7 @@ static int process_introspect(
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_set_free_free_ Set *s = NULL;
+ const char *previous_interface = NULL;
struct introspect intro;
struct node_vtable *c;
bool empty;
@@ -768,11 +769,24 @@ static int process_introspect(
empty = false;
- r = introspect_write_interface(&intro, c->interface, c->vtable);
+ if (!streq_ptr(previous_interface, c->interface)) {
+
+ if (previous_interface)
+ fputs(" </interface>\n", intro.f);
+
+ fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
+ }
+
+ r = introspect_write_interface(&intro, c->vtable);
if (r < 0)
goto finish;
+
+ previous_interface = c->interface;
}
+ if (previous_interface)
+ fputs(" </interface>\n", intro.f);
+
if (empty) {
/* Nothing?, let's see if we exist at all, and if not
* refuse to do anything */
@@ -806,51 +820,6 @@ finish:
return r;
}
-static int object_manager_serialize_vtable(
- sd_bus *bus,
- sd_bus_message *reply,
- const char *path,
- struct node_vtable *c,
- sd_bus_error *error,
- void *userdata) {
-
- int r;
-
- assert(bus);
- assert(reply);
- assert(path);
- assert(c);
- assert(error);
-
- r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "s", c->interface);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "{sv}");
- if (r < 0)
- return r;
-
- r = vtable_append_all_properties(bus, reply, path, c, userdata, error);
- if (r < 0)
- return r;
- if (bus->nodes_modified)
- return 0;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- return 0;
-}
-
static int object_manager_serialize_path(
sd_bus *bus,
sd_bus_message *reply,
@@ -859,9 +828,10 @@ static int object_manager_serialize_path(
bool require_fallback,
sd_bus_error *error) {
+ const char *previous_interface = NULL;
+ bool found_something = false;
struct node_vtable *i;
struct node *n;
- bool found_something = false;
int r;
assert(bus);
@@ -889,6 +859,9 @@ static int object_manager_serialize_path(
continue;
if (!found_something) {
+
+ /* Open the object part */
+
r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
if (r < 0)
return r;
@@ -904,13 +877,54 @@ static int object_manager_serialize_path(
found_something = true;
}
- r = object_manager_serialize_vtable(bus, reply, path, i, error, u);
+ if (!streq_ptr(previous_interface, i->interface)) {
+
+ /* Maybe close the previous interface part */
+
+ if (previous_interface) {
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+ }
+
+ /* Open the new interface part */
+
+ r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "s", i->interface);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "{sv}");
+ if (r < 0)
+ return r;
+ }
+
+ r = vtable_append_all_properties(bus, reply, path, i, u, error);
if (r < 0)
return r;
if (sd_bus_error_is_set(error))
return 0;
if (bus->nodes_modified)
return 0;
+
+ previous_interface = i->interface;
+ }
+
+ if (previous_interface) {
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
}
if (found_something) {
@@ -1503,7 +1517,7 @@ static int add_object_vtable_internal(
sd_bus_object_find_t find,
void *userdata) {
- struct node_vtable *c = NULL, *i;
+ struct node_vtable *c = NULL, *i, *existing = NULL;
const sd_bus_vtable *v;
struct node *n;
int r;
@@ -1515,6 +1529,10 @@ static int add_object_vtable_internal(
assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
+ !streq(interface, "org.freedesktop.DBus.Introspectable") &&
+ !streq(interface, "org.freedesktop.DBus.Peer") &&
+ !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
r = hashmap_ensure_allocated(&bus->vtable_methods, vtable_member_hash_func, vtable_member_compare_func);
if (r < 0)
@@ -1529,15 +1547,20 @@ static int add_object_vtable_internal(
return -ENOMEM;
LIST_FOREACH(vtables, i, n->vtables) {
- if (streq(i->interface, interface)) {
- r = -EEXIST;
- goto fail;
- }
-
if (i->is_fallback != fallback) {
r = -EPROTOTYPE;
goto fail;
}
+
+ if (streq(i->interface, interface)) {
+
+ if (i->vtable == vtable) {
+ r = -EEXIST;
+ goto fail;
+ }
+
+ existing = i;
+ }
}
c = new0(struct node_vtable, 1);
@@ -1654,7 +1677,7 @@ static int add_object_vtable_internal(
}
}
- LIST_PREPEND(vtables, n->vtables, c);
+ LIST_INSERT_AFTER(vtables, n->vtables, existing, c);
bus->nodes_modified = true;
return 0;
@@ -1671,7 +1694,10 @@ static int remove_object_vtable_internal(
sd_bus *bus,
const char *path,
const char *interface,
- bool fallback) {
+ const sd_bus_vtable *vtable,
+ bool fallback,
+ sd_bus_object_find_t find,
+ void *userdata) {
struct node_vtable *c;
struct node *n;
@@ -1686,7 +1712,11 @@ static int remove_object_vtable_internal(
return 0;
LIST_FOREACH(vtables, c, n->vtables)
- if (streq(c->interface, interface) && c->is_fallback == fallback)
+ if (streq(c->interface, interface) &&
+ c->is_fallback == fallback &&
+ c->vtable == vtable &&
+ c->find == find &&
+ c->userdata == userdata)
break;
if (!c)
@@ -1715,9 +1745,11 @@ _public_ int sd_bus_add_object_vtable(
_public_ int sd_bus_remove_object_vtable(
sd_bus *bus,
const char *path,
- const char *interface) {
+ const char *interface,
+ const sd_bus_vtable *vtable,
+ void *userdata) {
- return remove_object_vtable_internal(bus, path, interface, false);
+ return remove_object_vtable_internal(bus, path, interface, vtable, false, NULL, userdata);
}
_public_ int sd_bus_add_fallback_vtable(
@@ -1734,9 +1766,12 @@ _public_ int sd_bus_add_fallback_vtable(
_public_ int sd_bus_remove_fallback_vtable(
sd_bus *bus,
const char *path,
- const char *interface) {
+ const char *interface,
+ const sd_bus_vtable *vtable,
+ sd_bus_object_find_t find,
+ void *userdata) {
- return remove_object_vtable_internal(bus, path, interface, true);
+ return remove_object_vtable_internal(bus, path, interface, vtable, true, find, userdata);
}
_public_ int sd_bus_add_node_enumerator(
@@ -1824,8 +1859,8 @@ static int emit_properties_changed_on_interface(
char **names) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- bool has_invalidating = false;
- struct vtable_member key;
+ bool has_invalidating = false, has_changing = false;
+ struct vtable_member key = {};
struct node_vtable *c;
struct node *n;
char **property;
@@ -1841,23 +1876,6 @@ static int emit_properties_changed_on_interface(
if (!n)
return 0;
- LIST_FOREACH(vtables, c, n->vtables) {
- if (require_fallback && !c->is_fallback)
- continue;
-
- if (streq(c->interface, interface))
- break;
- }
-
- if (!c)
- return 0;
-
- r = node_vtable_get_userdata(bus, path, c, &u);
- if (r <= 0)
- return r;
- if (bus->nodes_modified)
- return 0;
-
r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
if (r < 0)
return r;
@@ -1873,52 +1891,78 @@ static int emit_properties_changed_on_interface(
key.path = prefix;
key.interface = interface;
- STRV_FOREACH(property, names) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- struct vtable_member *v;
-
- assert_return(member_name_is_valid(*property), -EINVAL);
-
- key.member = *property;
- v = hashmap_get(bus->vtable_properties, &key);
- if (!v)
- return -ENOENT;
-
- assert(c == v->parent);
- assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM);
+ LIST_FOREACH(vtables, c, n->vtables) {
+ if (require_fallback && !c->is_fallback)
+ continue;
- if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
- has_invalidating = true;
+ if (!streq(c->interface, interface))
continue;
- }
- r = sd_bus_message_open_container(m, 'e', "sv");
+ r = node_vtable_get_userdata(bus, path, c, &u);
if (r < 0)
return r;
+ if (bus->nodes_modified)
+ return 0;
+ if (r == 0)
+ continue;
- r = sd_bus_message_append(m, "s", *property);
- if (r < 0)
- return r;
+ STRV_FOREACH(property, names) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ struct vtable_member *v;
- r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
- if (r < 0)
- return r;
+ assert_return(member_name_is_valid(*property), -EINVAL);
- r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
- if (r < 0)
- return r;
- if (bus->nodes_modified)
- return 0;
+ key.member = *property;
+ v = hashmap_get(bus->vtable_properties, &key);
+ if (!v)
+ return -ENOENT;
+
+ /* If there are two vtables for the same
+ * interface, let's handle this property when
+ * we come to that vtable. */
+ if (c != v->parent)
+ continue;
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return r;
+ assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE, -EDOM);
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return r;
+ if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY) {
+ has_invalidating = true;
+ continue;
+ }
+
+ has_changing = true;
+
+ r = sd_bus_message_open_container(m, 'e', "sv");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", *property);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'v', v->vtable->x.property.signature);
+ if (r < 0)
+ return r;
+
+ r = invoke_property_get(bus, v->vtable, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified)
+ return 0;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+ }
}
+ if (!has_invalidating && !has_changing)
+ return 0;
+
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
@@ -1928,19 +1972,35 @@ static int emit_properties_changed_on_interface(
return r;
if (has_invalidating) {
- STRV_FOREACH(property, names) {
- struct vtable_member *v;
-
- key.member = *property;
- assert_se(v = hashmap_get(bus->vtable_properties, &key));
- assert(c == v->parent);
+ LIST_FOREACH(vtables, c, n->vtables) {
+ if (require_fallback && !c->is_fallback)
+ continue;
- if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
+ if (!streq(c->interface, interface))
continue;
- r = sd_bus_message_append(m, "s", *property);
+ r = node_vtable_get_userdata(bus, path, c, &u);
if (r < 0)
return r;
+ if (bus->nodes_modified)
+ return 0;
+ if (r == 0)
+ continue;
+
+ STRV_FOREACH(property, names) {
+ struct vtable_member *v;
+
+ key.member = *property;
+ assert_se(v = hashmap_get(bus->vtable_properties, &key));
+ assert(c == v->parent);
+
+ if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY))
+ continue;
+
+ r = sd_bus_message_append(m, "s", *property);
+ if (r < 0)
+ return r;
+ }
}
}
@@ -2028,6 +2088,7 @@ static int interfaces_added_append_one_prefix(
bool require_fallback) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ bool found_interface = false;
struct node_vtable *c;
struct node *n;
void *u = NULL;
@@ -2047,38 +2108,43 @@ static int interfaces_added_append_one_prefix(
if (require_fallback && !c->is_fallback)
continue;
- if (streq(c->interface, interface))
- break;
- }
+ if (!streq(c->interface, interface))
+ continue;
- if (!c)
- return 0;
+ r = node_vtable_get_userdata(bus, path, c, &u);
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified)
+ return 0;
+ if (r == 0)
+ continue;
- r = node_vtable_get_userdata(bus, path, c, &u);
- if (r <= 0)
- return r;
- if (bus->nodes_modified)
- return 0;
+ if (!found_interface) {
+ r = sd_bus_message_append_basic(m, 's', interface);
+ if (r < 0)
+ return r;
- r = sd_bus_message_append_basic(m, 's', interface);
- if (r < 0)
- return r;
+ r = sd_bus_message_open_container(m, 'a', "{sv}");
+ if (r < 0)
+ return r;
- r = sd_bus_message_open_container(m, 'a', "{sv}");
- if (r < 0)
- return r;
+ found_interface = true;
+ }
- r = vtable_append_all_properties(bus, m,path, c, u, &error);
- if (r < 0)
- return r;
- if (bus->nodes_modified)
- return 0;
+ r = vtable_append_all_properties(bus, m, path, c, u, &error);
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified)
+ return 0;
+ }
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return r;
+ if (found_interface) {
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+ }
- return 1;
+ return found_interface;
}
static int interfaces_added_append_one(
diff --git a/src/libsystemd-bus/bus-signature.c b/src/libsystemd-bus/bus-signature.c
index 35c054baf6..1e5bf4821d 100644
--- a/src/libsystemd-bus/bus-signature.c
+++ b/src/libsystemd-bus/bus-signature.c
@@ -33,7 +33,10 @@ static int signature_element_length_internal(
int r;
- assert(s);
+ if (!s)
+ return -EINVAL;
+
+ assert(l);
if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
*l = 1;
@@ -114,7 +117,8 @@ bool signature_is_single(const char *s, bool allow_dict_entry) {
int r;
size_t t;
- assert(s);
+ if (!s)
+ return false;
r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t);
if (r < 0)
@@ -124,7 +128,9 @@ bool signature_is_single(const char *s, bool allow_dict_entry) {
}
bool signature_is_pair(const char *s) {
- assert(s);
+
+ if (!s)
+ return false;
if (!bus_type_is_basic(*s))
return false;
@@ -136,7 +142,8 @@ bool signature_is_valid(const char *s, bool allow_dict_entry) {
const char *p;
int r;
- assert(s);
+ if (!s)
+ return false;
p = s;
while (*p) {
diff --git a/src/libsystemd-bus/bus-util.c b/src/libsystemd-bus/bus-util.c
index ed6fdc473a..65323d0081 100644
--- a/src/libsystemd-bus/bus-util.c
+++ b/src/libsystemd-bus/bus-util.c
@@ -383,7 +383,7 @@ void bus_verify_polkit_async_registry_free(sd_bus *bus, Hashmap *registry) {
#endif
}
-static int bus_check_peercred(sd_bus *c) {
+int bus_check_peercred(sd_bus *c) {
struct ucred ucred;
socklen_t l;
int fd;
@@ -1014,7 +1014,8 @@ int bus_property_get_bool(
return sd_bus_message_append_basic(reply, 'b', &b);
}
-int bus_property_get_uid(
+#if __SIZEOF_SIZE_T__ != 8
+int bus_property_get_size(
sd_bus *bus,
const char *path,
const char *interface,
@@ -1023,12 +1024,41 @@ int bus_property_get_uid(
sd_bus_error *error,
void *userdata) {
- assert_cc(sizeof(uint32_t) == sizeof(uid_t));
- assert_cc(sizeof(uint32_t) == sizeof(gid_t));
- assert_cc(sizeof(uint32_t) == sizeof(pid_t));
+ uint64_t sz = *(size_t*) userdata;
- return sd_bus_message_append_basic(reply, 'u', userdata);
+ return sd_bus_message_append_basic(reply, 't', &sz);
}
+#endif
+
+#if __SIZEOF_LONG__ != 8
+int bus_property_get_long(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ sd_bus_error *error,
+ void *userdata) {
+
+ int64_t l = *(long*) userdata;
+
+ return sd_bus_message_append_basic(reply, 'x', &l);
+}
+
+int bus_property_get_ulong(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ sd_bus_error *error,
+ void *userdata) {
+
+ uint64_t ul = *(unsigned long*) userdata;
+
+ return sd_bus_message_append_basic(reply, 't', &ul);
+}
+#endif
int bus_log_parse_error(int r) {
log_error("Failed to parse message: %s", strerror(-r));
diff --git a/src/libsystemd-bus/bus-util.h b/src/libsystemd-bus/bus-util.h
index 314c2f7867..c8d5dd982e 100644
--- a/src/libsystemd-bus/bus-util.h
+++ b/src/libsystemd-bus/bus-util.h
@@ -55,7 +55,8 @@ int bus_map_all_properties(sd_bus *bus,
int bus_async_unregister_and_quit(sd_event *e, sd_bus *bus, const char *name);
int bus_event_loop_with_idle(sd_event *e, sd_bus *bus, const char *name, usec_t timeout);
-int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
+
+int bus_check_peercred(sd_bus *c);
int bus_verify_polkit(sd_bus *bus, sd_bus_message *m, const char *action, bool interactive, bool *_challenge, sd_bus_error *e);
@@ -71,11 +72,48 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us
int bus_print_property(const char *name, sd_bus_message *property, bool all);
int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
+int bus_property_get_tristate(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
-int bus_property_get_uid(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
-#define bus_property_get_gid bus_property_get_uid
-#define bus_property_get_pid bus_property_get_uid
+#define bus_property_get_usec ((sd_bus_property_get_t) NULL)
+#define bus_property_set_usec ((sd_bus_property_set_t) NULL)
+
+assert_cc(sizeof(int) == sizeof(int32_t));
+#define bus_property_get_int ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(unsigned) == sizeof(unsigned));
+#define bus_property_get_unsigned ((sd_bus_property_get_t) NULL)
+
+/* On 64bit machines we can use the default serializer for size_t and
+ * friends, otherwise we need to cast this manually */
+#if __SIZEOF_SIZE_T__ == 8
+#define bus_property_get_size ((sd_bus_property_get_t) NULL)
+#else
+int bus_property_get_size(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
+#endif
+
+#if __SIZEOF_LONG__ == 8
+#define bus_property_get_long ((sd_bus_property_get_t) NULL)
+#define bus_property_get_ulong ((sd_bus_property_get_t) NULL)
+#else
+int bus_property_get_long(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
+int bus_property_get_ulong(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata);
+#endif
+
+/* uid_t and friends on Linux 32 bit. This means we can just use the
+ * default serializer for 32bit unsigned, for serializing it, and map
+ * it to NULL here */
+assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+#define bus_property_get_uid ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+#define bus_property_get_gid ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(pid_t) == sizeof(uint32_t));
+#define bus_property_get_pid ((sd_bus_property_get_t) NULL)
+
+assert_cc(sizeof(mode_t) == sizeof(uint32_t));
+#define bus_property_get_mode ((sd_bus_property_get_t) NULL)
int bus_log_parse_error(int r);
int bus_log_create_error(int r);
@@ -129,22 +167,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref);
} \
struct __useless_struct_to_allow_trailing_semicolon__
-#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
-#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed"
-#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed"
-
-#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
-#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID"
-#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists"
-
-#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession"
-#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID"
-#define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser"
-#define BUS_ERROR_NO_USER_FOR_PID "org.freedesktop.login1.NoUserForPID"
-#define BUS_ERROR_NO_SUCH_SEAT "org.freedesktop.login1.NoSuchSeat"
-#define BUS_ERROR_SESSION_NOT_ON_SEAT "org.freedesktop.login1.SessionNotOnSeat"
-#define BUS_ERROR_NOT_IN_CONTROL "org.freedesktop.login1.NotInControl"
-#define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken"
-#define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken"
-#define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress"
-#define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported"
+#define BUS_PROPERTY_DUAL_TIMESTAMP(name, offset, flags) \
+ SD_BUS_PROPERTY(name, "t", bus_property_get_usec, offset + offsetof(struct dual_timestamp, realtime), flags), \
+ SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, offset + offsetof(struct dual_timestamp, monotonic), flags)
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index c8248e19aa..bc88ac977c 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -1204,6 +1204,18 @@ _public_ void sd_bus_close(sd_bus *bus) {
* freed. */
}
+static void bus_enter_closing(sd_bus *bus) {
+ assert(bus);
+
+ if (bus->state != BUS_OPENING &&
+ bus->state != BUS_AUTHENTICATING &&
+ bus->state != BUS_HELLO &&
+ bus->state != BUS_RUNNING)
+ return;
+
+ bus->state = BUS_CLOSING;
+}
+
_public_ sd_bus *sd_bus_ref(sd_bus *bus) {
assert_return(bus, NULL);
@@ -1282,6 +1294,20 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m) {
return bus_message_seal(m, ++b->serial);
}
+static int bus_write_message(sd_bus *bus, sd_bus_message *message, size_t *idx) {
+ int r;
+
+ assert(bus);
+ assert(message);
+
+ if (bus->is_kernel)
+ r = bus_kernel_write_message(bus, message);
+ else
+ r = bus_socket_write_message(bus, message, idx);
+
+ return r;
+}
+
static int dispatch_wqueue(sd_bus *bus) {
int r, ret = 0;
@@ -1290,15 +1316,10 @@ static int dispatch_wqueue(sd_bus *bus) {
while (bus->wqueue_size > 0) {
- 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);
+ r = bus_write_message(bus, bus->wqueue[0], &bus->windex);
+ if (r < 0)
return r;
- } else if (r == 0)
+ else if (r == 0)
/* Didn't do anything this time */
return ret;
else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
@@ -1324,6 +1345,20 @@ static int dispatch_wqueue(sd_bus *bus) {
return ret;
}
+static int bus_read_message(sd_bus *bus, sd_bus_message **m) {
+ int r;
+
+ assert(bus);
+ assert(m);
+
+ if (bus->is_kernel)
+ r = bus_kernel_read_message(bus, m);
+ else
+ r = bus_socket_read_message(bus, m);
+
+ return r;
+}
+
static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
sd_bus_message *z = NULL;
int r, ret = 0;
@@ -1343,15 +1378,9 @@ static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) {
/* Try to read a new message */
do {
- 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);
+ r = bus_read_message(bus, &z);
+ if (r < 0)
return r;
- }
if (r == 0)
return ret;
@@ -1395,15 +1424,10 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *serial) {
if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
size_t idx = 0;
- 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);
+ r = bus_write_message(bus, m, &idx);
+ if (r < 0)
return r;
- } else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) {
+ else if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) {
/* Wasn't fully written. So let's remember how
* much was written. Note that the first entry
* of the wqueue array is always allocated so
@@ -1573,7 +1597,7 @@ int bus_ensure_running(sd_bus *bus) {
assert(bus);
- if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED)
+ if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING)
return -ENOTCONN;
if (bus->state == BUS_RUNNING)
return 1;
@@ -1644,12 +1668,10 @@ _public_ int sd_bus_call(
room = true;
}
- if (bus->is_kernel)
- r = bus_kernel_read_message(bus, &incoming);
- else
- r = bus_socket_read_message(bus, &incoming);
+ r = bus_read_message(bus, &incoming);
if (r < 0)
return r;
+
if (incoming) {
if (incoming->reply_serial == serial) {
@@ -1731,7 +1753,6 @@ _public_ int sd_bus_call(
_public_ int sd_bus_get_fd(sd_bus *bus) {
assert_return(bus, -EINVAL);
- assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(bus->input_fd == bus->output_fd, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -1742,7 +1763,7 @@ _public_ int sd_bus_get_events(sd_bus *bus) {
int flags = 0;
assert_return(bus, -EINVAL);
- assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+ assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN);
assert_return(!bus_pid_changed(bus), -ECHILD);
if (bus->state == BUS_OPENING)
@@ -1769,9 +1790,14 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
assert_return(bus, -EINVAL);
assert_return(timeout_usec, -EINVAL);
- assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+ assert_return(BUS_IS_OPEN(bus->state) || bus->state == BUS_CLOSING, -ENOTCONN);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ if (bus->state == BUS_CLOSING) {
+ *timeout_usec = 0;
+ return 1;
+ }
+
if (bus->state == BUS_AUTHENTICATING) {
*timeout_usec = bus->auth_timeout;
return 1;
@@ -1821,12 +1847,21 @@ static int process_timeout(sd_bus *bus) {
if (r < 0)
return r;
+ r = bus_seal_message(bus, m);
+ if (r < 0)
+ return r;
+
assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
hashmap_remove(bus->reply_callbacks, &c->serial);
+ bus->current = m;
+ bus->iteration_counter ++;
+
r = c->callback(bus, m, c->userdata);
free(c);
+ bus->current = NULL;
+
return r < 0 ? r : 1;
}
@@ -1877,7 +1912,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
r = c->callback(bus, m, c->userdata);
free(c);
- return r;
+ return r < 0 ? r : 1;
}
static int process_filter(sd_bus *bus, sd_bus_message *m) {
@@ -2078,6 +2113,85 @@ null_message:
return r;
}
+static int process_closing(sd_bus *bus, sd_bus_message **ret) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ struct reply_callback *c;
+ int r;
+
+ assert(bus);
+ assert(bus->state == BUS_CLOSING);
+
+ c = hashmap_first(bus->reply_callbacks);
+ if (c) {
+ /* First, fail all outstanding method calls */
+ r = bus_message_new_synthetic_error(
+ bus,
+ c->serial,
+ &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_NO_REPLY, "Connection terminated"),
+ &m);
+ if (r < 0)
+ return r;
+
+ r = bus_seal_message(bus, m);
+ if (r < 0)
+ return r;
+
+ if (c->timeout != 0)
+ prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
+
+ hashmap_remove(bus->reply_callbacks, &c->serial);
+
+ bus->current = m;
+ bus->iteration_counter++;
+
+ r = c->callback(bus, m, c->userdata);
+ free(c);
+
+ if (r >= 0)
+ r = 1;
+
+ goto finish;
+ }
+
+ /* Then, synthesize a Disconnected message */
+ r = sd_bus_message_new_signal(
+ bus,
+ "/org/freedesktop/DBus/Local",
+ "org.freedesktop.DBus.Local",
+ "Disconnected",
+ &m);
+ if (r < 0)
+ return r;
+
+ r = bus_seal_message(bus, m);
+ if (r < 0)
+ return r;
+
+ sd_bus_close(bus);
+
+ bus->current = m;
+ bus->iteration_counter++;
+
+ r = process_filter(bus, m);
+ if (r != 0)
+ goto finish;
+
+ r = process_match(bus, m);
+ if (r != 0)
+ goto finish;
+
+ if (ret) {
+ *ret = m;
+ m = NULL;
+ }
+
+ r = 1;
+
+finish:
+ bus->current = NULL;
+ return r;
+}
+
_public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
BUS_DONT_DESTROY(bus);
int r;
@@ -2091,7 +2205,7 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
assert_return(!bus_pid_changed(bus), -ECHILD);
/* We don't allow recursively invoking sd_bus_process(). */
- assert_return(!bus->processing, -EBUSY);
+ assert_return(!bus->current, -EBUSY);
switch (bus->state) {
@@ -2101,29 +2215,43 @@ _public_ int sd_bus_process(sd_bus *bus, sd_bus_message **ret) {
case BUS_OPENING:
r = bus_socket_process_opening(bus);
- if (r < 0)
+ if (r == -ECONNRESET || r == -EPIPE) {
+ bus_enter_closing(bus);
+ r = 1;
+ } else if (r < 0)
return r;
if (ret)
*ret = NULL;
return r;
case BUS_AUTHENTICATING:
-
r = bus_socket_process_authenticating(bus);
- if (r < 0)
+ if (r == -ECONNRESET || r == -EPIPE) {
+ bus_enter_closing(bus);
+ r = 1;
+ } else if (r < 0)
return r;
+
if (ret)
*ret = NULL;
+
return r;
case BUS_RUNNING:
case BUS_HELLO:
-
- bus->processing = true;
r = process_running(bus, ret);
- bus->processing = false;
+ if (r == -ECONNRESET || r == -EPIPE) {
+ bus_enter_closing(bus);
+ r = 1;
+
+ if (ret)
+ *ret = NULL;
+ }
return r;
+
+ case BUS_CLOSING:
+ return process_closing(bus, ret);
}
assert_not_reached("Unknown state");
@@ -2136,6 +2264,10 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
usec_t m = (usec_t) -1;
assert(bus);
+
+ if (bus->state == BUS_CLOSING)
+ return 1;
+
assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
e = sd_bus_get_events(bus);
@@ -2186,9 +2318,13 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
_public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
assert_return(bus, -EINVAL);
- assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ if (bus->state == BUS_CLOSING)
+ return 0;
+
+ assert_return(BUS_IS_OPEN(bus->state) , -ENOTCONN);
+
if (bus->rqueue_size > 0)
return 0;
@@ -2199,9 +2335,13 @@ _public_ int sd_bus_flush(sd_bus *bus) {
int r;
assert_return(bus, -EINVAL);
- assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ if (bus->state == BUS_CLOSING)
+ return 0;
+
+ assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
+
r = bus_ensure_running(bus);
if (r < 0)
return r;
diff --git a/src/libsystemd-bus/sd-event.c b/src/libsystemd-bus/sd-event.c
index d01e82d945..5cb3bccc5a 100644
--- a/src/libsystemd-bus/sd-event.c
+++ b/src/libsystemd-bus/sd-event.c
@@ -51,7 +51,7 @@ struct sd_event_source {
sd_event *event;
void *userdata;
- sd_prepare_handler_t prepare;
+ sd_event_handler_t prepare;
EventSourceType type:4;
int enabled:3;
@@ -65,34 +65,34 @@ struct sd_event_source {
union {
struct {
- sd_io_handler_t callback;
+ sd_event_io_handler_t callback;
int fd;
uint32_t events;
uint32_t revents;
bool registered:1;
} io;
struct {
- sd_time_handler_t callback;
+ sd_event_time_handler_t callback;
usec_t next, accuracy;
unsigned earliest_index;
unsigned latest_index;
} time;
struct {
- sd_signal_handler_t callback;
+ sd_event_signal_handler_t callback;
struct signalfd_siginfo siginfo;
int sig;
} signal;
struct {
- sd_child_handler_t callback;
+ sd_event_child_handler_t callback;
siginfo_t siginfo;
pid_t pid;
int options;
} child;
struct {
- sd_defer_handler_t callback;
+ sd_event_handler_t callback;
} defer;
struct {
- sd_quit_handler_t callback;
+ sd_event_handler_t callback;
unsigned prioq_index;
} quit;
};
@@ -567,7 +567,7 @@ _public_ int sd_event_add_io(
sd_event *e,
int fd,
uint32_t events,
- sd_io_handler_t callback,
+ sd_event_io_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -655,7 +655,7 @@ static int event_add_time_internal(
Prioq **latest,
uint64_t usec,
uint64_t accuracy,
- sd_time_handler_t callback,
+ sd_event_time_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -722,7 +722,7 @@ fail:
_public_ int sd_event_add_monotonic(sd_event *e,
uint64_t usec,
uint64_t accuracy,
- sd_time_handler_t callback,
+ sd_event_time_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -732,7 +732,7 @@ _public_ int sd_event_add_monotonic(sd_event *e,
_public_ int sd_event_add_realtime(sd_event *e,
uint64_t usec,
uint64_t accuracy,
- sd_time_handler_t callback,
+ sd_event_time_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -774,7 +774,7 @@ static int event_update_signal_fd(sd_event *e) {
_public_ int sd_event_add_signal(
sd_event *e,
int sig,
- sd_signal_handler_t callback,
+ sd_event_signal_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -824,7 +824,7 @@ _public_ int sd_event_add_child(
sd_event *e,
pid_t pid,
int options,
- sd_child_handler_t callback,
+ sd_event_child_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -883,7 +883,7 @@ _public_ int sd_event_add_child(
_public_ int sd_event_add_defer(
sd_event *e,
- sd_defer_handler_t callback,
+ sd_event_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -916,7 +916,7 @@ _public_ int sd_event_add_defer(
_public_ int sd_event_add_quit(
sd_event *e,
- sd_quit_handler_t callback,
+ sd_event_handler_t callback,
void *userdata,
sd_event_source **ret) {
@@ -1297,7 +1297,7 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
return 0;
}
-_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_prepare_handler_t callback) {
+_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) {
int r;
assert_return(s, -EINVAL);
diff --git a/src/libsystemd-bus/test-bus-introspect.c b/src/libsystemd-bus/test-bus-introspect.c
index ae41618647..b9865349ac 100644
--- a/src/libsystemd-bus/test-bus-introspect.c
+++ b/src/libsystemd-bus/test-bus-introspect.c
@@ -52,7 +52,9 @@ int main(int argc, char *argv[]) {
assert_se(introspect_begin(&intro) >= 0);
- assert_se(introspect_write_interface(&intro, "org.foo", vtable) >= 0);
+ fprintf(intro.f, " <interface name=\"org.foo\">\n");
+ assert_se(introspect_write_interface(&intro, vtable) >= 0);
+ fputs(" </interface>\n", intro.f);
fflush(intro.f);
fputs(intro.introspection, stdout);
diff --git a/src/libsystemd-bus/test-bus-marshal.c b/src/libsystemd-bus/test-bus-marshal.c
index cbf5e1a0fa..b7606d7708 100644
--- a/src/libsystemd-bus/test-bus-marshal.c
+++ b/src/libsystemd-bus/test-bus-marshal.c
@@ -28,7 +28,7 @@
#endif
#ifdef HAVE_DBUS
-#include <dbus.h>
+#include <dbus/dbus.h>
#endif
#include "log.h"