diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-11-19 21:12:59 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-11-20 20:52:36 +0100 |
commit | 718db96199eb307751264e4163555662c9a389fa (patch) | |
tree | 9ec8467596ba1acba76bb6273c7797baf68c1a00 /src/libsystemd-bus | |
parent | 3febea3a0b0a968ea281e7959c1654cbaf95c9bf (diff) |
core: convert PID 1 to libsystemd-bus
This patch converts PID 1 to libsystemd-bus and thus drops the
dependency on libdbus. The only remaining code using libdbus is a test
case that validates our bus marshalling against libdbus' marshalling,
and this dependency can be turned off.
This patch also adds a couple of things to libsystem-bus, that are
necessary to make the port work:
- Synthesizing of "Disconnected" messages when bus connections are
severed.
- Support for attaching multiple vtables for the same interface on the
same path.
This patch also fixes the SetDefaultTarget() and GetDefaultTarget() bus
calls which used an inappropriate signature.
As a side effect we will now generate PropertiesChanged messages which
carry property contents, rather than just invalidation information.
Diffstat (limited to 'src/libsystemd-bus')
-rw-r--r-- | src/libsystemd-bus/bus-error.h | 2 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-internal.h | 4 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-introspect.c | 6 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-introspect.h | 2 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-message.c | 1 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-objects.c | 360 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-signature.c | 15 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-util.c | 42 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-util.h | 68 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 224 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-event.c | 32 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-introspect.c | 4 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-marshal.c | 2 |
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" |