chiark / gitweb /
bus: if a a Set() vtable callback of a writable is left NULL, try to do the right...
[elogind.git] / src / libsystemd-bus / sd-bus.c
index 795007acc4ae52ccb8199d9faea7efe2aa9e4f33..cebb07319af1916875c5ff6a76c03421cc572661 100644 (file)
@@ -2089,18 +2089,125 @@ static int method_callbacks_run(
         if (r < 0)
                 return r;
 
-        if (!streq(c->vtable->method.signature, signature)) {
+        if (!streq(strempty(c->vtable->method.signature), signature)) {
                 r = sd_bus_reply_method_errorf(bus, m,
                                                "org.freedesktop.DBus.Error.InvalidArgs",
                                                "Invalid arguments '%s' to call %s:%s, expecting '%s'.",
-                                               signature, c->interface, c->member, c->vtable->method.signature);
+                                               signature, c->interface, c->member, strempty(c->vtable->method.signature));
                 if (r < 0)
                         return r;
 
                 return 1;
         }
 
-        return c->vtable->method.handler(bus, m, u);
+        if (c->vtable->method.handler)
+                return c->vtable->method.handler(bus, m, u);
+
+        /* If the method callback is NULL, make this a successful NOP */
+        r = sd_bus_reply_method_return(bus, m, NULL);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int invoke_property_get(
+                sd_bus *bus,
+                const sd_bus_vtable *v,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *m,
+                sd_bus_error *error,
+                void *userdata) {
+
+        int r;
+        void *p;
+
+        assert(bus);
+        assert(v);
+
+        if (v->property.get)
+                return v->property.get(bus, path, interface, property, m, error, userdata);
+
+        /* Automatic handling if no callback is defined. */
+
+        assert(bus_type_is_basic(v->property.signature[0]));
+
+        switch (v->property.signature[0]) {
+
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_OBJECT_PATH:
+        case SD_BUS_TYPE_SIGNATURE:
+                p = *(char**) userdata;
+                break;
+
+        default:
+                p = userdata;
+                break;
+        }
+
+        r = sd_bus_message_append_basic(m, v->property.signature[0], p);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
+
+static int invoke_property_set(
+                sd_bus *bus,
+                const sd_bus_vtable *v,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *value,
+                sd_bus_error *error,
+                void *userdata) {
+
+        int r;
+
+        assert(bus);
+        assert(v);
+
+        if (v->property.set)
+                return v->property.set(bus, path, interface, property, value, error, userdata);
+
+        /*  Automatic handling if no callback is defined. */
+
+        assert(signature_is_single(v->property.signature, false));
+        assert(bus_type_is_basic(v->property.signature[0]));
+
+        switch (v->property.signature[0]) {
+
+        case SD_BUS_TYPE_STRING:
+        case SD_BUS_TYPE_OBJECT_PATH:
+        case SD_BUS_TYPE_SIGNATURE: {
+                const char *p;
+                char *n;
+
+                r = sd_bus_message_read_basic(value, v->property.signature[0], &p);
+                if (r < 0)
+                        return r;
+
+                n = strdup(p);
+                if (!n)
+                        return -ENOMEM;
+
+                free(*(char**) userdata);
+                *(char**) userdata = n;
+
+                break;
+        }
+
+        default:
+                r = sd_bus_message_read_basic(value, v->property.signature[0], userdata);
+                if (r < 0)
+                        return r;
+
+                break;
+        }
+
+        return 1;
 }
 
 static int property_get_set_callbacks_run(
@@ -2140,12 +2247,9 @@ static int property_get_set_callbacks_run(
                 if (r < 0)
                         return r;
 
-                if (c->vtable->property.get) {
-                        r = c->vtable->property.get(bus, m->path, c->interface, c->member, reply, &error, u);
-                        if (r < 0)
-                                return r;
-                } else
-                        assert_not_reached("automatic properties not supported yet");
+                r = invoke_property_get(bus, c->vtable, m->path, c->interface, c->member, reply, &error, u);
+                if (r < 0)
+                        return r;
 
                 if (sd_bus_error_is_set(&error)) {
                         r = sd_bus_reply_method_error(bus, m, &error);
@@ -2167,12 +2271,9 @@ static int property_get_set_callbacks_run(
                         if (r < 0)
                                 return r;
 
-                        if (c->vtable->property.set) {
-                                r = c->vtable->property.set(bus, m->path, c->interface, c->member, m, &error, u);
-                                if (r < 0)
-                                        return r;
-                        } else
-                                assert_not_reached("automatic properties not supported yet");
+                        r = invoke_property_set(bus, c->vtable, m->path, c->interface, c->member, m, &error, u);
+                        if (r < 0)
+                                return r;
                 }
 
                 if (sd_bus_error_is_set(&error)) {
@@ -2226,7 +2327,7 @@ static int vtable_append_all_properties(
                 if (r < 0)
                         return r;
 
-                r = v->property.get(bus, path, c->interface, v->property.member, reply, error, vtable_property_convert_userdata(v, userdata));
+                r = invoke_property_get(bus, v, path, c->interface, v->property.member, reply, error, vtable_property_convert_userdata(v, userdata));
                 if (r < 0)
                         return r;
 
@@ -2499,6 +2600,7 @@ static int object_manager_serialize_vtable(
 static int object_manager_serialize_path(
                 sd_bus *bus,
                 sd_bus_message *reply,
+                const char *prefix,
                 const char *path,
                 bool require_fallback,
                 sd_bus_error *error) {
@@ -2509,10 +2611,11 @@ static int object_manager_serialize_path(
 
         assert(bus);
         assert(reply);
+        assert(prefix);
         assert(path);
         assert(error);
 
-        n = hashmap_get(bus->nodes, path);
+        n = hashmap_get(bus->nodes, prefix);
         if (!n)
                 return 0;
 
@@ -2566,7 +2669,7 @@ static int object_manager_serialize_path_and_fallbacks(
         assert(error);
 
         /* First, add all vtables registered for this path */
-        r = object_manager_serialize_path(bus, reply, path, false, error);
+        r = object_manager_serialize_path(bus, reply, path, path, false, error);
         if (r < 0)
                 return r;
         if (sd_bus_error_is_set(error))
@@ -2587,7 +2690,7 @@ static int object_manager_serialize_path_and_fallbacks(
 
                         *e = 0;
 
-                        r = object_manager_serialize_path(bus, reply, p, true, error);
+                        r = object_manager_serialize_path(bus, reply, p, path, true, error);
                         if (r < 0)
                                 return r;
 
@@ -2687,7 +2790,13 @@ static int process_get_managed_objects(
         return 1;
 }
 
-static int object_find_and_run(sd_bus *bus, sd_bus_message *m, const char *p, bool require_fallback, bool *found_object) {
+static int object_find_and_run(
+                sd_bus *bus,
+                sd_bus_message *m,
+                const char *p,
+                bool require_fallback,
+                bool *found_object) {
+
         struct node *n;
         struct vtable_member vtable_key, *v;
         int r;
@@ -3390,7 +3499,6 @@ int sd_bus_emit_signal(
                 const char *types, ...) {
 
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        va_list ap;
         int r;
 
         if (!bus)
@@ -3404,11 +3512,15 @@ int sd_bus_emit_signal(
         if (r < 0)
                 return r;
 
-        va_start(ap, types);
-        r = bus_message_append_ap(m, types, ap);
-        va_end(ap);
-        if (r < 0)
-                return r;
+        if (!isempty(types)) {
+                va_list ap;
+
+                va_start(ap, types);
+                r = bus_message_append_ap(m, types, ap);
+                va_end(ap);
+                if (r < 0)
+                        return r;
+        }
 
         return sd_bus_send(bus, m, NULL);
 }
@@ -3424,7 +3536,6 @@ int sd_bus_call_method(
                 const char *types, ...) {
 
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        va_list ap;
         int r;
 
         if (!bus)
@@ -3439,11 +3550,15 @@ int sd_bus_call_method(
         if (r < 0)
                 return r;
 
-        va_start(ap, types);
-        r = bus_message_append_ap(m, types, ap);
-        va_end(ap);
-        if (r < 0)
-                return r;
+        if (!isempty(types)) {
+                va_list ap;
+
+                va_start(ap, types);
+                r = bus_message_append_ap(m, types, ap);
+                va_end(ap);
+                if (r < 0)
+                        return r;
+        }
 
         return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
 }
@@ -3454,7 +3569,6 @@ int sd_bus_reply_method_return(
                 const char *types, ...) {
 
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
-        va_list ap;
         int r;
 
         if (!bus)
@@ -3477,11 +3591,15 @@ int sd_bus_reply_method_return(
         if (r < 0)
                 return r;
 
-        va_start(ap, types);
-        r = bus_message_append_ap(m, types, ap);
-        va_end(ap);
-        if (r < 0)
-                return r;
+        if (!isempty(types)) {
+                va_list ap;
+
+                va_start(ap, types);
+                r = bus_message_append_ap(m, types, ap);
+                va_end(ap);
+                if (r < 0)
+                        return r;
+        }
 
         return sd_bus_send(bus, m, NULL);
 }
@@ -3571,7 +3689,7 @@ static void free_node_vtable(sd_bus *bus, struct node_vtable *w) {
         if (w->interface && w->node && w->vtable) {
                 const sd_bus_vtable *v;
 
-                for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; w++) {
+                for (v = w->vtable; v->type != _SD_BUS_VTABLE_END; v++) {
                         struct vtable_member *x = NULL;
 
                         switch (v->type) {
@@ -3705,9 +3823,9 @@ static int add_object_vtable_internal(
                         struct vtable_member *m;
 
                         if (!member_name_is_valid(v->method.member) ||
-                            !signature_is_valid(v->method.signature, false) ||
-                            !signature_is_valid(v->method.result, false) ||
-                            !v->method.handler ||
+                            !signature_is_valid(strempty(v->method.signature), false) ||
+                            !signature_is_valid(strempty(v->method.result), false) ||
+                            !(v->method.handler || (isempty(v->method.signature) && isempty(v->method.result))) ||
                             v->flags & (SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY)) {
                                 r = -EINVAL;
                                 goto fail;
@@ -3734,12 +3852,21 @@ static int add_object_vtable_internal(
                         break;
                 }
 
-                case _SD_BUS_VTABLE_PROPERTY:
-                case _SD_BUS_VTABLE_WRITABLE_PROPERTY: {
+                case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
+
+                        if (!(v->property.set || bus_type_is_basic(v->property.signature[0]))) {
+                                r = -EINVAL;
+                                goto fail;
+                        }
+
+                        /* Fall through */
+
+                case _SD_BUS_VTABLE_PROPERTY: {
                         struct vtable_member *m;
 
                         if (!member_name_is_valid(v->property.member) ||
                             !signature_is_single(v->property.signature, false) ||
+                            !(v->property.get || bus_type_is_basic(v->property.signature[0])) ||
                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
                             (v->flags & SD_BUS_VTABLE_PROPERTY_INVALIDATE_ONLY && !(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))) {
                                 r = -EINVAL;
@@ -3771,7 +3898,7 @@ static int add_object_vtable_internal(
                 case _SD_BUS_VTABLE_SIGNAL:
 
                         if (!member_name_is_valid(v->signal.member) ||
-                            !signature_is_single(v->signal.signature, false)) {
+                            !signature_is_single(strempty(v->signal.signature), false)) {
                                 r = -EINVAL;
                                 goto fail;
                         }
@@ -3792,7 +3919,7 @@ fail:
                 free_node_vtable(bus, c);
 
         bus_node_gc(bus, n);
-        return 0;
+        return r;
 }
 
 static int remove_object_vtable_internal(
@@ -3977,18 +4104,16 @@ static int emit_properties_changed_on_interface(
 
                 if (streq(c->interface, interface))
                         break;
-
-                r = node_vtable_get_userdata(bus, path, c, &u);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        break;
         }
 
         if (!c)
                 return 0;
 
-        r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus", "PropertiesChanged", &m);
+        r = node_vtable_get_userdata(bus, path, c, &u);
+        if (r <= 0)
+                return r;
+
+        r = sd_bus_message_new_signal(bus, path, "org.freedesktop.DBus.Properties", "PropertiesChanged", &m);
         if (r < 0)
                 return r;
 
@@ -4025,7 +4150,7 @@ static int emit_properties_changed_on_interface(
                 if (r < 0)
                         return r;
 
-                r = sd_bus_message_append(m, "s", *n);
+                r = sd_bus_message_append(m, "s", *property);
                 if (r < 0)
                         return r;
 
@@ -4033,7 +4158,7 @@ static int emit_properties_changed_on_interface(
                 if (r < 0)
                         return r;
 
-                r = v->vtable->property.get(bus, m->path, interface, *property, m, &error, vtable_property_convert_userdata(v->vtable, u));
+                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;