LCOV - code coverage report
Current view: top level - libsystemd/sd-bus - bus-objects.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 1155 1557 74.2 %
Date: 2015-07-29 18:47:03 Functions: 50 51 98.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include "strv.h"
      23             : #include "set.h"
      24             : #include "bus-internal.h"
      25             : #include "bus-message.h"
      26             : #include "bus-type.h"
      27             : #include "bus-signature.h"
      28             : #include "bus-introspect.h"
      29             : #include "bus-util.h"
      30             : #include "bus-slot.h"
      31             : #include "bus-objects.h"
      32             : 
      33          33 : static int node_vtable_get_userdata(
      34             :                 sd_bus *bus,
      35             :                 const char *path,
      36             :                 struct node_vtable *c,
      37             :                 void **userdata,
      38             :                 sd_bus_error *error) {
      39             : 
      40             :         sd_bus_slot *s;
      41             :         void *u;
      42             :         int r;
      43             : 
      44          33 :         assert(bus);
      45          33 :         assert(path);
      46          33 :         assert(c);
      47             : 
      48          33 :         s = container_of(c, sd_bus_slot, node_vtable);
      49          33 :         u = s->userdata;
      50          33 :         if (c->find) {
      51           0 :                 bus->current_slot = sd_bus_slot_ref(s);
      52           0 :                 bus->current_userdata = u;
      53           0 :                 r = c->find(bus, path, c->interface, u, &u, error);
      54           0 :                 bus->current_userdata = NULL;
      55           0 :                 bus->current_slot = sd_bus_slot_unref(s);
      56             : 
      57           0 :                 if (r < 0)
      58           0 :                         return r;
      59           0 :                 if (sd_bus_error_is_set(error))
      60           0 :                         return -sd_bus_error_get_errno(error);
      61           0 :                 if (r == 0)
      62           0 :                         return r;
      63             :         }
      64             : 
      65          33 :         if (userdata)
      66          28 :                 *userdata = u;
      67             : 
      68          33 :         return 1;
      69             : }
      70             : 
      71          10 : static void *vtable_method_convert_userdata(const sd_bus_vtable *p, void *u) {
      72          10 :         assert(p);
      73             : 
      74          10 :         return (uint8_t*) u + p->x.method.offset;
      75             : }
      76             : 
      77          38 : static void *vtable_property_convert_userdata(const sd_bus_vtable *p, void *u) {
      78          38 :         assert(p);
      79             : 
      80          38 :         return (uint8_t*) u + p->x.property.offset;
      81             : }
      82             : 
      83           6 : static int vtable_property_get_userdata(
      84             :                 sd_bus *bus,
      85             :                 const char *path,
      86             :                 struct vtable_member *p,
      87             :                 void **userdata,
      88             :                 sd_bus_error *error) {
      89             : 
      90             :         void *u;
      91             :         int r;
      92             : 
      93           6 :         assert(bus);
      94           6 :         assert(path);
      95           6 :         assert(p);
      96           6 :         assert(userdata);
      97             : 
      98           6 :         r = node_vtable_get_userdata(bus, path, p->parent, &u, error);
      99           6 :         if (r <= 0)
     100           0 :                 return r;
     101           6 :         if (bus->nodes_modified)
     102           0 :                 return 0;
     103             : 
     104           6 :         *userdata = vtable_property_convert_userdata(p->vtable, u);
     105           6 :         return 1;
     106             : }
     107             : 
     108           9 : static int add_enumerated_to_set(
     109             :                 sd_bus *bus,
     110             :                 const char *prefix,
     111             :                 struct node_enumerator *first,
     112             :                 Set *s,
     113             :                 sd_bus_error *error) {
     114             : 
     115             :         struct node_enumerator *c;
     116             :         int r;
     117             : 
     118           9 :         assert(bus);
     119           9 :         assert(prefix);
     120           9 :         assert(s);
     121             : 
     122          30 :         LIST_FOREACH(enumerators, c, first) {
     123           6 :                 char **children = NULL, **k;
     124             :                 sd_bus_slot *slot;
     125             : 
     126           6 :                 if (bus->nodes_modified)
     127           0 :                         return 0;
     128             : 
     129           6 :                 slot = container_of(c, sd_bus_slot, node_enumerator);
     130             : 
     131           6 :                 bus->current_slot = sd_bus_slot_ref(slot);
     132           6 :                 bus->current_userdata = slot->userdata;
     133           6 :                 r = c->callback(bus, prefix, slot->userdata, &children, error);
     134           6 :                 bus->current_userdata = NULL;
     135           6 :                 bus->current_slot = sd_bus_slot_unref(slot);
     136             : 
     137           6 :                 if (r < 0)
     138           0 :                         return r;
     139           6 :                 if (sd_bus_error_is_set(error))
     140           0 :                         return -sd_bus_error_get_errno(error);
     141             : 
     142          24 :                 STRV_FOREACH(k, children) {
     143          18 :                         if (r < 0) {
     144           0 :                                 free(*k);
     145           0 :                                 continue;
     146             :                         }
     147             : 
     148          18 :                         if (!object_path_is_valid(*k)){
     149           0 :                                 free(*k);
     150           0 :                                 r = -EINVAL;
     151           0 :                                 continue;
     152             :                         }
     153             : 
     154          18 :                         if (!object_path_startswith(*k, prefix)) {
     155           0 :                                 free(*k);
     156           0 :                                 continue;
     157             :                         }
     158             : 
     159          18 :                         r = set_consume(s, *k);
     160          18 :                         if (r == -EEXIST)
     161           0 :                                 r = 0;
     162             :                 }
     163             : 
     164           6 :                 free(children);
     165           6 :                 if (r < 0)
     166           0 :                         return r;
     167             :         }
     168             : 
     169           9 :         return 0;
     170             : }
     171             : 
     172           9 : static int add_subtree_to_set(
     173             :                 sd_bus *bus,
     174             :                 const char *prefix,
     175             :                 struct node *n,
     176             :                 bool skip_subhierarchies,
     177             :                 Set *s,
     178             :                 sd_bus_error *error) {
     179             : 
     180             :         struct node *i;
     181             :         int r;
     182             : 
     183           9 :         assert(bus);
     184           9 :         assert(prefix);
     185           9 :         assert(n);
     186           9 :         assert(s);
     187             : 
     188           9 :         r = add_enumerated_to_set(bus, prefix, n->enumerators, s, error);
     189           9 :         if (r < 0)
     190           0 :                 return r;
     191           9 :         if (bus->nodes_modified)
     192           0 :                 return 0;
     193             : 
     194          14 :         LIST_FOREACH(siblings, i, n->child) {
     195             :                 char *t;
     196             : 
     197           5 :                 if (!object_path_startswith(i->path, prefix))
     198           0 :                         continue;
     199             : 
     200           5 :                 t = strdup(i->path);
     201           5 :                 if (!t)
     202           0 :                         return -ENOMEM;
     203             : 
     204           5 :                 r = set_consume(s, t);
     205           5 :                 if (r < 0 && r != -EEXIST)
     206           0 :                         return r;
     207             : 
     208           5 :                 if (!skip_subhierarchies || !i->object_managers) {
     209           4 :                         r = add_subtree_to_set(bus, prefix, i, skip_subhierarchies, s, error);
     210           4 :                         if (r < 0)
     211           0 :                                 return r;
     212           4 :                         if (bus->nodes_modified)
     213           0 :                                 return 0;
     214             :                 }
     215             :         }
     216             : 
     217           9 :         return 0;
     218             : }
     219             : 
     220           5 : static int get_child_nodes(
     221             :                 sd_bus *bus,
     222             :                 const char *prefix,
     223             :                 struct node *n,
     224             :                 bool skip_subhierarchies,
     225             :                 Set **_s,
     226             :                 sd_bus_error *error) {
     227             : 
     228           5 :         Set *s = NULL;
     229             :         int r;
     230             : 
     231           5 :         assert(bus);
     232           5 :         assert(prefix);
     233           5 :         assert(n);
     234           5 :         assert(_s);
     235             : 
     236           5 :         s = set_new(&string_hash_ops);
     237           5 :         if (!s)
     238           0 :                 return -ENOMEM;
     239             : 
     240           5 :         r = add_subtree_to_set(bus, prefix, n, skip_subhierarchies, s, error);
     241           5 :         if (r < 0) {
     242           0 :                 set_free_free(s);
     243           0 :                 return r;
     244             :         }
     245             : 
     246           5 :         *_s = s;
     247           5 :         return 0;
     248             : }
     249             : 
     250          36 : static int node_callbacks_run(
     251             :                 sd_bus *bus,
     252             :                 sd_bus_message *m,
     253             :                 struct node_callback *first,
     254             :                 bool require_fallback,
     255             :                 bool *found_object) {
     256             : 
     257             :         struct node_callback *c;
     258             :         int r;
     259             : 
     260          36 :         assert(bus);
     261          36 :         assert(m);
     262          36 :         assert(found_object);
     263             : 
     264          36 :         LIST_FOREACH(callbacks, c, first) {
     265           2 :                 _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
     266             :                 sd_bus_slot *slot;
     267             : 
     268           1 :                 if (bus->nodes_modified)
     269           0 :                         return 0;
     270             : 
     271           1 :                 if (require_fallback && !c->is_fallback)
     272           0 :                         continue;
     273             : 
     274           1 :                 *found_object = true;
     275             : 
     276           1 :                 if (c->last_iteration == bus->iteration_counter)
     277           0 :                         continue;
     278             : 
     279           1 :                 c->last_iteration = bus->iteration_counter;
     280             : 
     281           1 :                 r = sd_bus_message_rewind(m, true);
     282           1 :                 if (r < 0)
     283           0 :                         return r;
     284             : 
     285           1 :                 slot = container_of(c, sd_bus_slot, node_callback);
     286             : 
     287           1 :                 bus->current_slot = sd_bus_slot_ref(slot);
     288           1 :                 bus->current_handler = c->callback;
     289           1 :                 bus->current_userdata = slot->userdata;
     290           1 :                 r = c->callback(m, slot->userdata, &error_buffer);
     291           1 :                 bus->current_userdata = NULL;
     292           1 :                 bus->current_handler = NULL;
     293           1 :                 bus->current_slot = sd_bus_slot_unref(slot);
     294             : 
     295           1 :                 r = bus_maybe_reply_error(m, r, &error_buffer);
     296           1 :                 if (r != 0)
     297           1 :                         return r;
     298             :         }
     299             : 
     300          35 :         return 0;
     301             : }
     302             : 
     303             : #define CAPABILITY_SHIFT(x) (((x) >> __builtin_ctzll(_SD_BUS_VTABLE_CAPABILITY_MASK)) & 0xFFFF)
     304             : 
     305          13 : static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c, sd_bus_error *error) {
     306             :         uint64_t cap;
     307             :         int r;
     308             : 
     309          13 :         assert(bus);
     310          13 :         assert(m);
     311          13 :         assert(c);
     312             : 
     313             :         /* If the entire bus is trusted let's grant access */
     314          13 :         if (bus->trusted)
     315           0 :                 return 0;
     316             : 
     317             :         /* If the member is marked UNPRIVILEGED let's grant access */
     318          13 :         if (c->vtable->flags & SD_BUS_VTABLE_UNPRIVILEGED)
     319           0 :                 return 0;
     320             : 
     321             :         /* Check have the caller has the requested capability
     322             :          * set. Note that the flags value contains the capability
     323             :          * number plus one, which we need to subtract here. We do this
     324             :          * so that we have 0 as special value for "default
     325             :          * capability". */
     326          13 :         cap = CAPABILITY_SHIFT(c->vtable->flags);
     327          13 :         if (cap == 0)
     328          13 :                 cap = CAPABILITY_SHIFT(c->parent->vtable[0].flags);
     329          13 :         if (cap == 0)
     330          13 :                 cap = CAP_SYS_ADMIN;
     331             :         else
     332           0 :                 cap --;
     333             : 
     334          13 :         r = sd_bus_query_sender_privilege(m, cap);
     335          13 :         if (r < 0)
     336           0 :                 return r;
     337          13 :         if (r > 0)
     338          13 :                 return 0;
     339             : 
     340           0 :         return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access to %s.%s() not permitted.", c->interface, c->member);
     341             : }
     342             : 
     343          10 : static int method_callbacks_run(
     344             :                 sd_bus *bus,
     345             :                 sd_bus_message *m,
     346             :                 struct vtable_member *c,
     347             :                 bool require_fallback,
     348             :                 bool *found_object) {
     349             : 
     350          20 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     351             :         const char *signature;
     352             :         void *u;
     353             :         int r;
     354             : 
     355          10 :         assert(bus);
     356          10 :         assert(m);
     357          10 :         assert(c);
     358          10 :         assert(found_object);
     359             : 
     360          10 :         if (require_fallback && !c->parent->is_fallback)
     361           0 :                 return 0;
     362             : 
     363          10 :         r = check_access(bus, m, c, &error);
     364          10 :         if (r < 0)
     365           0 :                 return bus_maybe_reply_error(m, r, &error);
     366             : 
     367          10 :         r = node_vtable_get_userdata(bus, m->path, c->parent, &u, &error);
     368          10 :         if (r <= 0)
     369           0 :                 return bus_maybe_reply_error(m, r, &error);
     370          10 :         if (bus->nodes_modified)
     371           0 :                 return 0;
     372             : 
     373          10 :         u = vtable_method_convert_userdata(c->vtable, u);
     374             : 
     375          10 :         *found_object = true;
     376             : 
     377          10 :         if (c->last_iteration == bus->iteration_counter)
     378           0 :                 return 0;
     379             : 
     380          10 :         c->last_iteration = bus->iteration_counter;
     381             : 
     382          10 :         r = sd_bus_message_rewind(m, true);
     383          10 :         if (r < 0)
     384           0 :                 return r;
     385             : 
     386          10 :         signature = sd_bus_message_get_signature(m, true);
     387          10 :         if (!signature)
     388           0 :                 return -EINVAL;
     389             : 
     390          10 :         if (!streq(strempty(c->vtable->x.method.signature), signature))
     391           1 :                 return sd_bus_reply_method_errorf(
     392             :                                 m,
     393             :                                 SD_BUS_ERROR_INVALID_ARGS,
     394             :                                 "Invalid arguments '%s' to call %s.%s(), expecting '%s'.",
     395           1 :                                 signature, c->interface, c->member, strempty(c->vtable->x.method.signature));
     396             : 
     397             :         /* Keep track what the signature of the reply to this message
     398             :          * should be, so that this can be enforced when sealing the
     399             :          * reply. */
     400           9 :         m->enforced_reply_signature = strempty(c->vtable->x.method.result);
     401             : 
     402           9 :         if (c->vtable->x.method.handler) {
     403             :                 sd_bus_slot *slot;
     404             : 
     405           8 :                 slot = container_of(c->parent, sd_bus_slot, node_vtable);
     406             : 
     407           8 :                 bus->current_slot = sd_bus_slot_ref(slot);
     408           8 :                 bus->current_handler = c->vtable->x.method.handler;
     409           8 :                 bus->current_userdata = u;
     410           8 :                 r = c->vtable->x.method.handler(m, u, &error);
     411           8 :                 bus->current_userdata = NULL;
     412           8 :                 bus->current_handler = NULL;
     413           8 :                 bus->current_slot = sd_bus_slot_unref(slot);
     414             : 
     415           8 :                 return bus_maybe_reply_error(m, r, &error);
     416             :         }
     417             : 
     418             :         /* If the method callback is NULL, make this a successful NOP */
     419           1 :         r = sd_bus_reply_method_return(m, NULL);
     420           1 :         if (r < 0)
     421           0 :                 return r;
     422             : 
     423           1 :         return 1;
     424             : }
     425             : 
     426          35 : static int invoke_property_get(
     427             :                 sd_bus *bus,
     428             :                 sd_bus_slot *slot,
     429             :                 const sd_bus_vtable *v,
     430             :                 const char *path,
     431             :                 const char *interface,
     432             :                 const char *property,
     433             :                 sd_bus_message *reply,
     434             :                 void *userdata,
     435             :                 sd_bus_error *error) {
     436             : 
     437             :         const void *p;
     438             :         int r;
     439             : 
     440          35 :         assert(bus);
     441          35 :         assert(slot);
     442          35 :         assert(v);
     443          35 :         assert(path);
     444          35 :         assert(interface);
     445          35 :         assert(property);
     446          35 :         assert(reply);
     447             : 
     448          35 :         if (v->x.property.get) {
     449             : 
     450          31 :                 bus->current_slot = sd_bus_slot_ref(slot);
     451          31 :                 bus->current_userdata = userdata;
     452          31 :                 r = v->x.property.get(bus, path, interface, property, reply, userdata, error);
     453          31 :                 bus->current_userdata = NULL;
     454          31 :                 bus->current_slot = sd_bus_slot_unref(slot);
     455             : 
     456          31 :                 if (r < 0)
     457           0 :                         return r;
     458          31 :                 if (sd_bus_error_is_set(error))
     459           0 :                         return -sd_bus_error_get_errno(error);
     460          31 :                 return r;
     461             :         }
     462             : 
     463             :         /* Automatic handling if no callback is defined. */
     464             : 
     465           4 :         if (streq(v->x.property.signature, "as"))
     466           0 :                 return sd_bus_message_append_strv(reply, *(char***) userdata);
     467             : 
     468           4 :         assert(signature_is_single(v->x.property.signature, false));
     469           4 :         assert(bus_type_is_basic(v->x.property.signature[0]));
     470             : 
     471           4 :         switch (v->x.property.signature[0]) {
     472             : 
     473             :         case SD_BUS_TYPE_STRING:
     474             :         case SD_BUS_TYPE_SIGNATURE:
     475           2 :                 p = strempty(*(char**) userdata);
     476           2 :                 break;
     477             : 
     478             :         case SD_BUS_TYPE_OBJECT_PATH:
     479           0 :                 p = *(char**) userdata;
     480           0 :                 assert(p);
     481           0 :                 break;
     482             : 
     483             :         default:
     484           2 :                 p = userdata;
     485           2 :                 break;
     486             :         }
     487             : 
     488           4 :         return sd_bus_message_append_basic(reply, v->x.property.signature[0], p);
     489             : }
     490             : 
     491           3 : static int invoke_property_set(
     492             :                 sd_bus *bus,
     493             :                 sd_bus_slot *slot,
     494             :                 const sd_bus_vtable *v,
     495             :                 const char *path,
     496             :                 const char *interface,
     497             :                 const char *property,
     498             :                 sd_bus_message *value,
     499             :                 void *userdata,
     500             :                 sd_bus_error *error) {
     501             : 
     502             :         int r;
     503             : 
     504           3 :         assert(bus);
     505           3 :         assert(slot);
     506           3 :         assert(v);
     507           3 :         assert(path);
     508           3 :         assert(interface);
     509           3 :         assert(property);
     510           3 :         assert(value);
     511             : 
     512           3 :         if (v->x.property.set) {
     513             : 
     514           1 :                 bus->current_slot = sd_bus_slot_ref(slot);
     515           1 :                 bus->current_userdata = userdata;
     516           1 :                 r = v->x.property.set(bus, path, interface, property, value, userdata, error);
     517           1 :                 bus->current_userdata = NULL;
     518           1 :                 bus->current_slot = sd_bus_slot_unref(slot);
     519             : 
     520           1 :                 if (r < 0)
     521           0 :                         return r;
     522           1 :                 if (sd_bus_error_is_set(error))
     523           0 :                         return -sd_bus_error_get_errno(error);
     524           1 :                 return r;
     525             :         }
     526             : 
     527             :         /*  Automatic handling if no callback is defined. */
     528             : 
     529           2 :         assert(signature_is_single(v->x.property.signature, false));
     530           2 :         assert(bus_type_is_basic(v->x.property.signature[0]));
     531             : 
     532           2 :         switch (v->x.property.signature[0]) {
     533             : 
     534             :         case SD_BUS_TYPE_STRING:
     535             :         case SD_BUS_TYPE_OBJECT_PATH:
     536             :         case SD_BUS_TYPE_SIGNATURE: {
     537             :                 const char *p;
     538             :                 char *n;
     539             : 
     540           1 :                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], &p);
     541           1 :                 if (r < 0)
     542           0 :                         return r;
     543             : 
     544           1 :                 n = strdup(p);
     545           1 :                 if (!n)
     546           0 :                         return -ENOMEM;
     547             : 
     548           1 :                 free(*(char**) userdata);
     549           1 :                 *(char**) userdata = n;
     550             : 
     551           1 :                 break;
     552             :         }
     553             : 
     554             :         default:
     555           1 :                 r = sd_bus_message_read_basic(value, v->x.property.signature[0], userdata);
     556           1 :                 if (r < 0)
     557           0 :                         return r;
     558             : 
     559           1 :                 break;
     560             :         }
     561             : 
     562           2 :         return 1;
     563             : }
     564             : 
     565           6 : static int property_get_set_callbacks_run(
     566             :                 sd_bus *bus,
     567             :                 sd_bus_message *m,
     568             :                 struct vtable_member *c,
     569             :                 bool require_fallback,
     570             :                 bool is_get,
     571             :                 bool *found_object) {
     572             : 
     573          12 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     574          12 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     575             :         sd_bus_slot *slot;
     576           6 :         void *u = NULL;
     577             :         int r;
     578             : 
     579           6 :         assert(bus);
     580           6 :         assert(m);
     581           6 :         assert(c);
     582           6 :         assert(found_object);
     583             : 
     584           6 :         if (require_fallback && !c->parent->is_fallback)
     585           0 :                 return 0;
     586             : 
     587           6 :         r = vtable_property_get_userdata(bus, m->path, c, &u, &error);
     588           6 :         if (r <= 0)
     589           0 :                 return bus_maybe_reply_error(m, r, &error);
     590           6 :         if (bus->nodes_modified)
     591           0 :                 return 0;
     592             : 
     593           6 :         slot = container_of(c->parent, sd_bus_slot, node_vtable);
     594             : 
     595           6 :         *found_object = true;
     596             : 
     597           6 :         r = sd_bus_message_new_method_return(m, &reply);
     598           6 :         if (r < 0)
     599           0 :                 return r;
     600             : 
     601           6 :         if (is_get) {
     602             :                 /* Note that we do not protect against reexecution
     603             :                  * here (using the last_iteration check, see below),
     604             :                  * should the node tree have changed and we got called
     605             :                  * again. We assume that property Get() calls are
     606             :                  * ultimately without side-effects or if they aren't
     607             :                  * then at least idempotent. */
     608             : 
     609           3 :                 r = sd_bus_message_open_container(reply, 'v', c->vtable->x.property.signature);
     610           3 :                 if (r < 0)
     611           0 :                         return r;
     612             : 
     613             :                 /* Note that we do not do an access check here. Read
     614             :                  * access to properties is always unrestricted, since
     615             :                  * PropertiesChanged signals broadcast contents
     616             :                  * anyway. */
     617             : 
     618           3 :                 r = invoke_property_get(bus, slot, c->vtable, m->path, c->interface, c->member, reply, u, &error);
     619           3 :                 if (r < 0)
     620           0 :                         return bus_maybe_reply_error(m, r, &error);
     621             : 
     622           3 :                 if (bus->nodes_modified)
     623           0 :                         return 0;
     624             : 
     625           3 :                 r = sd_bus_message_close_container(reply);
     626           3 :                 if (r < 0)
     627           0 :                         return r;
     628             : 
     629             :         } else {
     630           3 :                 const char *signature = NULL;
     631           3 :                 char type = 0;
     632             : 
     633           3 :                 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
     634           0 :                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
     635             : 
     636             :                 /* Avoid that we call the set routine more than once
     637             :                  * if the processing of this message got restarted
     638             :                  * because the node tree changed. */
     639           3 :                 if (c->last_iteration == bus->iteration_counter)
     640           0 :                         return 0;
     641             : 
     642           3 :                 c->last_iteration = bus->iteration_counter;
     643             : 
     644           3 :                 r = sd_bus_message_peek_type(m, &type, &signature);
     645           3 :                 if (r < 0)
     646           0 :                         return r;
     647             : 
     648           3 :                 if (type != 'v' || !streq(strempty(signature), strempty(c->vtable->x.property.signature)))
     649           0 :                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Incorrect parameters for property '%s', expected '%s', got '%s'.", c->member, strempty(c->vtable->x.property.signature), strempty(signature));
     650             : 
     651           3 :                 r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
     652           3 :                 if (r < 0)
     653           0 :                         return r;
     654             : 
     655           3 :                 r = check_access(bus, m, c, &error);
     656           3 :                 if (r < 0)
     657           0 :                         return bus_maybe_reply_error(m, r, &error);
     658             : 
     659           3 :                 r = invoke_property_set(bus, slot, c->vtable, m->path, c->interface, c->member, m, u, &error);
     660           3 :                 if (r < 0)
     661           0 :                         return bus_maybe_reply_error(m, r, &error);
     662             : 
     663           3 :                 if (bus->nodes_modified)
     664           0 :                         return 0;
     665             : 
     666           3 :                 r = sd_bus_message_exit_container(m);
     667           3 :                 if (r < 0)
     668           0 :                         return r;
     669             :         }
     670             : 
     671           6 :         r = sd_bus_send(bus, reply, NULL);
     672           6 :         if (r < 0)
     673           0 :                 return r;
     674             : 
     675           6 :         return 1;
     676             : }
     677             : 
     678          32 : static int vtable_append_one_property(
     679             :                 sd_bus *bus,
     680             :                 sd_bus_message *reply,
     681             :                 const char *path,
     682             :                 struct node_vtable *c,
     683             :                 const sd_bus_vtable *v,
     684             :                 void *userdata,
     685             :                 sd_bus_error *error) {
     686             : 
     687             :         sd_bus_slot *slot;
     688             :         int r;
     689             : 
     690          32 :         assert(bus);
     691          32 :         assert(reply);
     692          32 :         assert(path);
     693          32 :         assert(c);
     694          32 :         assert(v);
     695             : 
     696          32 :         r = sd_bus_message_open_container(reply, 'e', "sv");
     697          32 :         if (r < 0)
     698           0 :                 return r;
     699             : 
     700          32 :         r = sd_bus_message_append(reply, "s", v->x.property.member);
     701          32 :         if (r < 0)
     702           0 :                 return r;
     703             : 
     704          32 :         r = sd_bus_message_open_container(reply, 'v', v->x.property.signature);
     705          32 :         if (r < 0)
     706           0 :                 return r;
     707             : 
     708          32 :         slot = container_of(c, sd_bus_slot, node_vtable);
     709             : 
     710          32 :         r = invoke_property_get(bus, slot, v, path, c->interface, v->x.property.member, reply, vtable_property_convert_userdata(v, userdata), error);
     711          32 :         if (r < 0)
     712           0 :                 return r;
     713          32 :         if (bus->nodes_modified)
     714           0 :                 return 0;
     715             : 
     716          32 :         r = sd_bus_message_close_container(reply);
     717          32 :         if (r < 0)
     718           0 :                 return r;
     719             : 
     720          32 :         r = sd_bus_message_close_container(reply);
     721          32 :         if (r < 0)
     722           0 :                 return r;
     723             : 
     724          32 :         return 0;
     725             : }
     726             : 
     727           8 : static int vtable_append_all_properties(
     728             :                 sd_bus *bus,
     729             :                 sd_bus_message *reply,
     730             :                 const char *path,
     731             :                 struct node_vtable *c,
     732             :                 void *userdata,
     733             :                 sd_bus_error *error) {
     734             : 
     735             :         const sd_bus_vtable *v;
     736             :         int r;
     737             : 
     738           8 :         assert(bus);
     739           8 :         assert(reply);
     740           8 :         assert(path);
     741           8 :         assert(c);
     742             : 
     743           8 :         if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
     744           0 :                 return 1;
     745             : 
     746          64 :         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
     747          56 :                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
     748          26 :                         continue;
     749             : 
     750          30 :                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
     751           0 :                         continue;
     752             : 
     753          30 :                 r = vtable_append_one_property(bus, reply, path, c, v, userdata, error);
     754          30 :                 if (r < 0)
     755           0 :                         return r;
     756          30 :                 if (bus->nodes_modified)
     757           0 :                         return 0;
     758             :         }
     759             : 
     760           8 :         return 1;
     761             : }
     762             : 
     763           2 : static int property_get_all_callbacks_run(
     764             :                 sd_bus *bus,
     765             :                 sd_bus_message *m,
     766             :                 struct node_vtable *first,
     767             :                 bool require_fallback,
     768             :                 const char *iface,
     769             :                 bool *found_object) {
     770             : 
     771           4 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     772             :         struct node_vtable *c;
     773             :         bool found_interface;
     774             :         int r;
     775             : 
     776           2 :         assert(bus);
     777           2 :         assert(m);
     778           2 :         assert(found_object);
     779             : 
     780           2 :         r = sd_bus_message_new_method_return(m, &reply);
     781           2 :         if (r < 0)
     782           0 :                 return r;
     783             : 
     784           2 :         r = sd_bus_message_open_container(reply, 'a', "{sv}");
     785           2 :         if (r < 0)
     786           0 :                 return r;
     787             : 
     788           3 :         found_interface = !iface ||
     789           2 :                 streq(iface, "org.freedesktop.DBus.Properties") ||
     790           4 :                 streq(iface, "org.freedesktop.DBus.Peer") ||
     791           1 :                 streq(iface, "org.freedesktop.DBus.Introspectable");
     792             : 
     793           4 :         LIST_FOREACH(vtables, c, first) {
     794           4 :                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     795             :                 void *u;
     796             : 
     797           2 :                 if (require_fallback && !c->is_fallback)
     798           0 :                         continue;
     799             : 
     800           2 :                 r = node_vtable_get_userdata(bus, m->path, c, &u, &error);
     801           2 :                 if (r < 0)
     802           0 :                         return bus_maybe_reply_error(m, r, &error);
     803           2 :                 if (bus->nodes_modified)
     804           0 :                         return 0;
     805           2 :                 if (r == 0)
     806           0 :                         continue;
     807             : 
     808           2 :                 *found_object = true;
     809             : 
     810           2 :                 if (iface && !streq(c->interface, iface))
     811           0 :                         continue;
     812           2 :                 found_interface = true;
     813             : 
     814           2 :                 r = vtable_append_all_properties(bus, reply, m->path, c, u, &error);
     815           2 :                 if (r < 0)
     816           0 :                         return bus_maybe_reply_error(m, r, &error);
     817           2 :                 if (bus->nodes_modified)
     818           0 :                         return 0;
     819             :         }
     820             : 
     821           2 :         if (!found_interface) {
     822           1 :                 r = sd_bus_reply_method_errorf(
     823             :                                 m,
     824             :                                 SD_BUS_ERROR_UNKNOWN_INTERFACE,
     825             :                                 "Unknown interface '%s'.", iface);
     826           1 :                 if (r < 0)
     827           0 :                         return r;
     828             : 
     829           1 :                 return 1;
     830             :         }
     831             : 
     832           1 :         r = sd_bus_message_close_container(reply);
     833           1 :         if (r < 0)
     834           0 :                 return r;
     835             : 
     836           1 :         r = sd_bus_send(bus, reply, NULL);
     837           1 :         if (r < 0)
     838           0 :                 return r;
     839             : 
     840           1 :         return 1;
     841             : }
     842             : 
     843          10 : static int bus_node_exists(
     844             :                 sd_bus *bus,
     845             :                 struct node *n,
     846             :                 const char *path,
     847             :                 bool require_fallback) {
     848             : 
     849             :         struct node_vtable *c;
     850             :         struct node_callback *k;
     851             :         int r;
     852             : 
     853          10 :         assert(bus);
     854          10 :         assert(n);
     855          10 :         assert(path);
     856             : 
     857             :         /* Tests if there's anything attached directly to this node
     858             :          * for the specified path */
     859             : 
     860          10 :         if (!require_fallback && (n->enumerators || n->object_managers))
     861           2 :                 return true;
     862             : 
     863          16 :         LIST_FOREACH(callbacks, k, n->callbacks) {
     864           0 :                 if (require_fallback && !k->is_fallback)
     865           0 :                         continue;
     866             : 
     867           0 :                 return 1;
     868             :         }
     869             : 
     870           8 :         LIST_FOREACH(vtables, c, n->vtables) {
     871           4 :                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     872             : 
     873           2 :                 if (require_fallback && !c->is_fallback)
     874           0 :                         continue;
     875             : 
     876           2 :                 r = node_vtable_get_userdata(bus, path, c, NULL, &error);
     877           2 :                 if (r != 0)
     878           2 :                         return r;
     879           0 :                 if (bus->nodes_modified)
     880           0 :                         return 0;
     881             :         }
     882             : 
     883           6 :         return 0;
     884             : }
     885             : 
     886           4 : static int process_introspect(
     887             :                 sd_bus *bus,
     888             :                 sd_bus_message *m,
     889             :                 struct node *n,
     890             :                 bool require_fallback,
     891             :                 bool *found_object) {
     892             : 
     893           8 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     894           8 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
     895           8 :         _cleanup_set_free_free_ Set *s = NULL;
     896           4 :         const char *previous_interface = NULL;
     897             :         struct introspect intro;
     898             :         struct node_vtable *c;
     899             :         bool empty;
     900             :         int r;
     901             : 
     902           4 :         assert(bus);
     903           4 :         assert(m);
     904           4 :         assert(n);
     905           4 :         assert(found_object);
     906             : 
     907           4 :         r = get_child_nodes(bus, m->path, n, false, &s, &error);
     908           4 :         if (r < 0)
     909           0 :                 return bus_maybe_reply_error(m, r, &error);
     910           4 :         if (bus->nodes_modified)
     911           0 :                 return 0;
     912             : 
     913           4 :         r = introspect_begin(&intro, bus->trusted);
     914           4 :         if (r < 0)
     915           0 :                 return r;
     916             : 
     917           4 :         r = introspect_write_default_interfaces(&intro, !require_fallback && n->object_managers);
     918           4 :         if (r < 0)
     919           0 :                 return r;
     920             : 
     921           4 :         empty = set_isempty(s);
     922             : 
     923           7 :         LIST_FOREACH(vtables, c, n->vtables) {
     924           3 :                 if (require_fallback && !c->is_fallback)
     925           0 :                         continue;
     926             : 
     927           3 :                 r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
     928           3 :                 if (r < 0) {
     929           0 :                         r = bus_maybe_reply_error(m, r, &error);
     930           0 :                         goto finish;
     931             :                 }
     932           3 :                 if (bus->nodes_modified) {
     933           0 :                         r = 0;
     934           0 :                         goto finish;
     935             :                 }
     936           3 :                 if (r == 0)
     937           0 :                         continue;
     938             : 
     939           3 :                 empty = false;
     940             : 
     941           3 :                 if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
     942           0 :                         continue;
     943             : 
     944           3 :                 if (!streq_ptr(previous_interface, c->interface)) {
     945             : 
     946           3 :                         if (previous_interface)
     947           1 :                                 fputs(" </interface>\n", intro.f);
     948             : 
     949           3 :                         fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
     950             :                 }
     951             : 
     952           3 :                 r = introspect_write_interface(&intro, c->vtable);
     953           3 :                 if (r < 0)
     954           0 :                         goto finish;
     955             : 
     956           3 :                 previous_interface = c->interface;
     957             :         }
     958             : 
     959           4 :         if (previous_interface)
     960           2 :                 fputs(" </interface>\n", intro.f);
     961             : 
     962           4 :         if (empty) {
     963             :                 /* Nothing?, let's see if we exist at all, and if not
     964             :                  * refuse to do anything */
     965           0 :                 r = bus_node_exists(bus, n, m->path, require_fallback);
     966           0 :                 if (r <= 0)
     967           0 :                         goto finish;
     968           0 :                 if (bus->nodes_modified) {
     969           0 :                         r = 0;
     970           0 :                         goto finish;
     971             :                 }
     972             :         }
     973             : 
     974           4 :         *found_object = true;
     975             : 
     976           4 :         r = introspect_write_child_nodes(&intro, s, m->path);
     977           4 :         if (r < 0)
     978           0 :                 goto finish;
     979             : 
     980           4 :         r = introspect_finish(&intro, bus, m, &reply);
     981           4 :         if (r < 0)
     982           0 :                 goto finish;
     983             : 
     984           4 :         r = sd_bus_send(bus, reply, NULL);
     985           4 :         if (r < 0)
     986           0 :                 goto finish;
     987             : 
     988           4 :         r = 1;
     989             : 
     990             : finish:
     991           4 :         introspect_free(&intro);
     992           4 :         return r;
     993             : }
     994             : 
     995          11 : static int object_manager_serialize_path(
     996             :                 sd_bus *bus,
     997             :                 sd_bus_message *reply,
     998             :                 const char *prefix,
     999             :                 const char *path,
    1000             :                 bool require_fallback,
    1001             :                 sd_bus_error *error) {
    1002             : 
    1003          11 :         const char *previous_interface = NULL;
    1004          11 :         bool found_something = false;
    1005             :         struct node_vtable *i;
    1006             :         struct node *n;
    1007             :         int r;
    1008             : 
    1009          11 :         assert(bus);
    1010          11 :         assert(reply);
    1011          11 :         assert(prefix);
    1012          11 :         assert(path);
    1013          11 :         assert(error);
    1014             : 
    1015          11 :         n = hashmap_get(bus->nodes, prefix);
    1016          11 :         if (!n)
    1017           2 :                 return 0;
    1018             : 
    1019          13 :         LIST_FOREACH(vtables, i, n->vtables) {
    1020             :                 void *u;
    1021             : 
    1022           4 :                 if (require_fallback && !i->is_fallback)
    1023           0 :                         continue;
    1024             : 
    1025           4 :                 r = node_vtable_get_userdata(bus, path, i, &u, error);
    1026           4 :                 if (r < 0)
    1027           0 :                         return r;
    1028           4 :                 if (bus->nodes_modified)
    1029           0 :                         return 0;
    1030           4 :                 if (r == 0)
    1031           0 :                         continue;
    1032             : 
    1033           4 :                 if (!found_something) {
    1034             : 
    1035             :                         /* Open the object part */
    1036             : 
    1037           4 :                         r = sd_bus_message_open_container(reply, 'e', "oa{sa{sv}}");
    1038           4 :                         if (r < 0)
    1039           0 :                                 return r;
    1040             : 
    1041           4 :                         r = sd_bus_message_append(reply, "o", path);
    1042           4 :                         if (r < 0)
    1043           0 :                                 return r;
    1044             : 
    1045           4 :                         r = sd_bus_message_open_container(reply, 'a', "{sa{sv}}");
    1046           4 :                         if (r < 0)
    1047           0 :                                 return r;
    1048             : 
    1049           4 :                         found_something = true;
    1050             :                 }
    1051             : 
    1052           4 :                 if (!streq_ptr(previous_interface, i->interface)) {
    1053             : 
    1054             :                         /* Maybe close the previous interface part */
    1055             : 
    1056           4 :                         if (previous_interface) {
    1057           0 :                                 r = sd_bus_message_close_container(reply);
    1058           0 :                                 if (r < 0)
    1059           0 :                                         return r;
    1060             : 
    1061           0 :                                 r = sd_bus_message_close_container(reply);
    1062           0 :                                 if (r < 0)
    1063           0 :                                         return r;
    1064             :                         }
    1065             : 
    1066             :                         /* Open the new interface part */
    1067             : 
    1068           4 :                         r = sd_bus_message_open_container(reply, 'e', "sa{sv}");
    1069           4 :                         if (r < 0)
    1070           0 :                                 return r;
    1071             : 
    1072           4 :                         r = sd_bus_message_append(reply, "s", i->interface);
    1073           4 :                         if (r < 0)
    1074           0 :                                 return r;
    1075             : 
    1076           4 :                         r = sd_bus_message_open_container(reply, 'a', "{sv}");
    1077           4 :                         if (r < 0)
    1078           0 :                                 return r;
    1079             :                 }
    1080             : 
    1081           4 :                 r = vtable_append_all_properties(bus, reply, path, i, u, error);
    1082           4 :                 if (r < 0)
    1083           0 :                         return r;
    1084           4 :                 if (bus->nodes_modified)
    1085           0 :                         return 0;
    1086             : 
    1087           4 :                 previous_interface = i->interface;
    1088             :         }
    1089             : 
    1090           9 :         if (previous_interface) {
    1091           4 :                 r = sd_bus_message_close_container(reply);
    1092           4 :                 if (r < 0)
    1093           0 :                         return r;
    1094             : 
    1095           4 :                 r = sd_bus_message_close_container(reply);
    1096           4 :                 if (r < 0)
    1097           0 :                         return r;
    1098             :         }
    1099             : 
    1100           9 :         if (found_something) {
    1101           4 :                 r = sd_bus_message_close_container(reply);
    1102           4 :                 if (r < 0)
    1103           0 :                         return r;
    1104             : 
    1105           4 :                 r = sd_bus_message_close_container(reply);
    1106           4 :                 if (r < 0)
    1107           0 :                         return r;
    1108             :         }
    1109             : 
    1110           9 :         return 1;
    1111             : }
    1112             : 
    1113           4 : static int object_manager_serialize_path_and_fallbacks(
    1114             :                 sd_bus *bus,
    1115             :                 sd_bus_message *reply,
    1116             :                 const char *path,
    1117             :                 sd_bus_error *error) {
    1118             : 
    1119             :         char *prefix;
    1120             :         int r;
    1121             : 
    1122           4 :         assert(bus);
    1123           4 :         assert(reply);
    1124           4 :         assert(path);
    1125           4 :         assert(error);
    1126             : 
    1127             :         /* First, add all vtables registered for this path */
    1128           4 :         r = object_manager_serialize_path(bus, reply, path, path, false, error);
    1129           4 :         if (r < 0)
    1130           0 :                 return r;
    1131           4 :         if (bus->nodes_modified)
    1132           0 :                 return 0;
    1133             : 
    1134             :         /* Second, add fallback vtables registered for any of the prefixes */
    1135           4 :         prefix = alloca(strlen(path) + 1);
    1136          11 :         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
    1137           7 :                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
    1138           7 :                 if (r < 0)
    1139           0 :                         return r;
    1140           7 :                 if (bus->nodes_modified)
    1141           0 :                         return 0;
    1142             :         }
    1143             : 
    1144           4 :         return 0;
    1145             : }
    1146             : 
    1147           3 : static int process_get_managed_objects(
    1148             :                 sd_bus *bus,
    1149             :                 sd_bus_message *m,
    1150             :                 struct node *n,
    1151             :                 bool require_fallback,
    1152             :                 bool *found_object) {
    1153             : 
    1154           6 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1155           6 :         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
    1156           6 :         _cleanup_set_free_free_ Set *s = NULL;
    1157             :         Iterator i;
    1158             :         char *path;
    1159             :         int r;
    1160             : 
    1161           3 :         assert(bus);
    1162           3 :         assert(m);
    1163           3 :         assert(n);
    1164           3 :         assert(found_object);
    1165             : 
    1166             :         /* Spec says, GetManagedObjects() is only implemented on the root of a
    1167             :          * sub-tree. Therefore, we require a registered object-manager on
    1168             :          * exactly the queried path, otherwise, we refuse to respond. */
    1169             : 
    1170           3 :         if (require_fallback || !n->object_managers)
    1171           2 :                 return 0;
    1172             : 
    1173           1 :         r = get_child_nodes(bus, m->path, n, true, &s, &error);
    1174           1 :         if (r < 0)
    1175           0 :                 return r;
    1176           1 :         if (bus->nodes_modified)
    1177           0 :                 return 0;
    1178             : 
    1179           1 :         r = set_put_strdup(s, m->path);
    1180           1 :         if (r < 0)
    1181           0 :                 return r;
    1182             : 
    1183           1 :         r = sd_bus_message_new_method_return(m, &reply);
    1184           1 :         if (r < 0)
    1185           0 :                 return r;
    1186             : 
    1187           1 :         r = sd_bus_message_open_container(reply, 'a', "{oa{sa{sv}}}");
    1188           1 :         if (r < 0)
    1189           0 :                 return r;
    1190             : 
    1191           6 :         SET_FOREACH(path, s, i) {
    1192           4 :                 r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
    1193           4 :                 if (r < 0)
    1194           0 :                         return r;
    1195             : 
    1196           4 :                 if (bus->nodes_modified)
    1197           0 :                         return 0;
    1198             :         }
    1199             : 
    1200           1 :         r = sd_bus_message_close_container(reply);
    1201           1 :         if (r < 0)
    1202           0 :                 return r;
    1203             : 
    1204           1 :         r = sd_bus_send(bus, reply, NULL);
    1205           1 :         if (r < 0)
    1206           0 :                 return r;
    1207             : 
    1208           1 :         return 1;
    1209             : }
    1210             : 
    1211          39 : static int object_find_and_run(
    1212             :                 sd_bus *bus,
    1213             :                 sd_bus_message *m,
    1214             :                 const char *p,
    1215             :                 bool require_fallback,
    1216             :                 bool *found_object) {
    1217             : 
    1218             :         struct node *n;
    1219             :         struct vtable_member vtable_key, *v;
    1220             :         int r;
    1221             : 
    1222          39 :         assert(bus);
    1223          39 :         assert(m);
    1224          39 :         assert(p);
    1225          39 :         assert(found_object);
    1226             : 
    1227          39 :         n = hashmap_get(bus->nodes, p);
    1228          39 :         if (!n)
    1229           3 :                 return 0;
    1230             : 
    1231             :         /* First, try object callbacks */
    1232          36 :         r = node_callbacks_run(bus, m, n->callbacks, require_fallback, found_object);
    1233          36 :         if (r != 0)
    1234           1 :                 return r;
    1235          35 :         if (bus->nodes_modified)
    1236           0 :                 return 0;
    1237             : 
    1238          35 :         if (!m->interface || !m->member)
    1239           0 :                 return 0;
    1240             : 
    1241             :         /* Then, look for a known method */
    1242          35 :         vtable_key.path = (char*) p;
    1243          35 :         vtable_key.interface = m->interface;
    1244          35 :         vtable_key.member = m->member;
    1245             : 
    1246          35 :         v = hashmap_get(bus->vtable_methods, &vtable_key);
    1247          35 :         if (v) {
    1248          10 :                 r = method_callbacks_run(bus, m, v, require_fallback, found_object);
    1249          10 :                 if (r != 0)
    1250          10 :                         return r;
    1251           0 :                 if (bus->nodes_modified)
    1252           0 :                         return 0;
    1253             :         }
    1254             : 
    1255             :         /* Then, look for a known property */
    1256          25 :         if (streq(m->interface, "org.freedesktop.DBus.Properties")) {
    1257           8 :                 bool get = false;
    1258             : 
    1259           8 :                 get = streq(m->member, "Get");
    1260             : 
    1261           8 :                 if (get || streq(m->member, "Set")) {
    1262             : 
    1263           6 :                         r = sd_bus_message_rewind(m, true);
    1264           6 :                         if (r < 0)
    1265           0 :                                 return r;
    1266             : 
    1267           6 :                         vtable_key.path = (char*) p;
    1268             : 
    1269           6 :                         r = sd_bus_message_read(m, "ss", &vtable_key.interface, &vtable_key.member);
    1270           6 :                         if (r < 0)
    1271           0 :                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface and member parameters");
    1272             : 
    1273           6 :                         v = hashmap_get(bus->vtable_properties, &vtable_key);
    1274           6 :                         if (v) {
    1275           6 :                                 r = property_get_set_callbacks_run(bus, m, v, require_fallback, get, found_object);
    1276           6 :                                 if (r != 0)
    1277           6 :                                         return r;
    1278             :                         }
    1279             : 
    1280           2 :                 } else if (streq(m->member, "GetAll")) {
    1281             :                         const char *iface;
    1282             : 
    1283           2 :                         r = sd_bus_message_rewind(m, true);
    1284           2 :                         if (r < 0)
    1285           2 :                                 return r;
    1286             : 
    1287           2 :                         r = sd_bus_message_read(m, "s", &iface);
    1288           2 :                         if (r < 0)
    1289           0 :                                 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected interface parameter");
    1290             : 
    1291           2 :                         if (iface[0] == 0)
    1292           1 :                                 iface = NULL;
    1293             : 
    1294           2 :                         r = property_get_all_callbacks_run(bus, m, n->vtables, require_fallback, iface, found_object);
    1295           2 :                         if (r != 0)
    1296           2 :                                 return r;
    1297             :                 }
    1298             : 
    1299          17 :         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
    1300             : 
    1301           4 :                 if (!isempty(sd_bus_message_get_signature(m, true)))
    1302           0 :                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
    1303             : 
    1304           4 :                 r = process_introspect(bus, m, n, require_fallback, found_object);
    1305           4 :                 if (r != 0)
    1306           4 :                         return r;
    1307             : 
    1308          13 :         } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.ObjectManager", "GetManagedObjects")) {
    1309             : 
    1310           3 :                 if (!isempty(sd_bus_message_get_signature(m, true)))
    1311           0 :                         return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
    1312             : 
    1313           3 :                 r = process_get_managed_objects(bus, m, n, require_fallback, found_object);
    1314           3 :                 if (r != 0)
    1315           1 :                         return r;
    1316             :         }
    1317             : 
    1318          12 :         if (bus->nodes_modified)
    1319           0 :                 return 0;
    1320             : 
    1321          12 :         if (!*found_object) {
    1322          10 :                 r = bus_node_exists(bus, n, m->path, require_fallback);
    1323          10 :                 if (r < 0)
    1324           0 :                         return r;
    1325          10 :                 if (bus->nodes_modified)
    1326           0 :                         return 0;
    1327          10 :                 if (r > 0)
    1328           4 :                         *found_object = true;
    1329             :         }
    1330             : 
    1331          12 :         return 0;
    1332             : }
    1333             : 
    1334       15552 : int bus_process_object(sd_bus *bus, sd_bus_message *m) {
    1335             :         int r;
    1336             :         size_t pl;
    1337       15552 :         bool found_object = false;
    1338             : 
    1339       15552 :         assert(bus);
    1340       15552 :         assert(m);
    1341             : 
    1342       15552 :         if (bus->hello_flags & KDBUS_HELLO_MONITOR)
    1343           0 :                 return 0;
    1344             : 
    1345       15552 :         if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
    1346          29 :                 return 0;
    1347             : 
    1348       15523 :         if (hashmap_isempty(bus->nodes))
    1349       15491 :                 return 0;
    1350             : 
    1351             :         /* Never respond to broadcast messages */
    1352          32 :         if (bus->bus_client && !m->destination)
    1353           0 :                 return 0;
    1354             : 
    1355          32 :         assert(m->path);
    1356          32 :         assert(m->member);
    1357             : 
    1358          32 :         pl = strlen(m->path);
    1359          32 :         do {
    1360          32 :                 char prefix[pl+1];
    1361             : 
    1362          32 :                 bus->nodes_modified = false;
    1363             : 
    1364          32 :                 r = object_find_and_run(bus, m, m->path, false, &found_object);
    1365          32 :                 if (r != 0)
    1366          20 :                         return r;
    1367             : 
    1368             :                 /* Look for fallback prefixes */
    1369          15 :                 OBJECT_PATH_FOREACH_PREFIX(prefix, m->path) {
    1370             : 
    1371           7 :                         if (bus->nodes_modified)
    1372           0 :                                 break;
    1373             : 
    1374           7 :                         r = object_find_and_run(bus, m, prefix, true, &found_object);
    1375           7 :                         if (r != 0)
    1376           4 :                                 return r;
    1377             :                 }
    1378             : 
    1379           8 :         } while (bus->nodes_modified);
    1380             : 
    1381           8 :         if (!found_object)
    1382           6 :                 return 0;
    1383             : 
    1384           4 :         if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Get") ||
    1385           2 :             sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "Set"))
    1386           0 :                 r = sd_bus_reply_method_errorf(
    1387             :                                 m,
    1388             :                                 SD_BUS_ERROR_UNKNOWN_PROPERTY,
    1389             :                                 "Unknown property or interface.");
    1390             :         else
    1391           2 :                 r = sd_bus_reply_method_errorf(
    1392             :                                 m,
    1393             :                                 SD_BUS_ERROR_UNKNOWN_METHOD,
    1394             :                                 "Unknown method '%s' or interface '%s'.", m->member, m->interface);
    1395             : 
    1396           2 :         if (r < 0)
    1397           0 :                 return r;
    1398             : 
    1399           2 :         return 1;
    1400             : }
    1401             : 
    1402          13 : static struct node *bus_node_allocate(sd_bus *bus, const char *path) {
    1403             :         struct node *n, *parent;
    1404             :         const char *e;
    1405          26 :         _cleanup_free_ char *s = NULL;
    1406             :         char *p;
    1407             :         int r;
    1408             : 
    1409          13 :         assert(bus);
    1410          13 :         assert(path);
    1411          13 :         assert(path[0] == '/');
    1412             : 
    1413          13 :         n = hashmap_get(bus->nodes, path);
    1414          13 :         if (n)
    1415           6 :                 return n;
    1416             : 
    1417           7 :         r = hashmap_ensure_allocated(&bus->nodes, &string_hash_ops);
    1418           7 :         if (r < 0)
    1419           0 :                 return NULL;
    1420             : 
    1421           7 :         s = strdup(path);
    1422           7 :         if (!s)
    1423           0 :                 return NULL;
    1424             : 
    1425           7 :         if (streq(path, "/"))
    1426           2 :                 parent = NULL;
    1427             :         else {
    1428           5 :                 e = strrchr(path, '/');
    1429           5 :                 assert(e);
    1430             : 
    1431           5 :                 p = strndupa(path, MAX(1, e - path));
    1432             : 
    1433           5 :                 parent = bus_node_allocate(bus, p);
    1434           5 :                 if (!parent)
    1435           0 :                         return NULL;
    1436             :         }
    1437             : 
    1438           7 :         n = new0(struct node, 1);
    1439           7 :         if (!n)
    1440           0 :                 return NULL;
    1441             : 
    1442           7 :         n->parent = parent;
    1443           7 :         n->path = s;
    1444           7 :         s = NULL; /* do not free */
    1445             : 
    1446           7 :         r = hashmap_put(bus->nodes, n->path, n);
    1447           7 :         if (r < 0) {
    1448           0 :                 free(n->path);
    1449           0 :                 free(n);
    1450           0 :                 return NULL;
    1451             :         }
    1452             : 
    1453           7 :         if (parent)
    1454           5 :                 LIST_PREPEND(siblings, parent->child, n);
    1455             : 
    1456           7 :         return n;
    1457             : }
    1458             : 
    1459          15 : void bus_node_gc(sd_bus *b, struct node *n) {
    1460          15 :         assert(b);
    1461             : 
    1462          15 :         if (!n)
    1463           2 :                 return;
    1464             : 
    1465          24 :         if (n->child ||
    1466          22 :             n->callbacks ||
    1467          19 :             n->vtables ||
    1468          15 :             n->enumerators ||
    1469           7 :             n->object_managers)
    1470           6 :                 return;
    1471             : 
    1472           7 :         assert(hashmap_remove(b->nodes, n->path) == n);
    1473             : 
    1474           7 :         if (n->parent)
    1475           5 :                 LIST_REMOVE(siblings, n->parent->child, n);
    1476             : 
    1477           7 :         free(n->path);
    1478           7 :         bus_node_gc(b, n->parent);
    1479           7 :         free(n);
    1480             : }
    1481             : 
    1482           4 : static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const char *path) {
    1483             :         struct node *n;
    1484             : 
    1485           4 :         assert(bus);
    1486           4 :         assert(path);
    1487             : 
    1488           4 :         n = hashmap_get(bus->nodes, path);
    1489           4 :         if (!n) {
    1490             :                 char *prefix;
    1491             : 
    1492           4 :                 prefix = alloca(strlen(path) + 1);
    1493           4 :                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
    1494           4 :                         n = hashmap_get(bus->nodes, prefix);
    1495           4 :                         if (n)
    1496           4 :                                 break;
    1497             :                 }
    1498             :         }
    1499             : 
    1500           8 :         while (n && !n->object_managers)
    1501           0 :                 n = n->parent;
    1502             : 
    1503           4 :         if (out)
    1504           4 :                 *out = n;
    1505           4 :         return !!n;
    1506             : }
    1507             : 
    1508           1 : static int bus_add_object(
    1509             :                 sd_bus *bus,
    1510             :                 sd_bus_slot **slot,
    1511             :                 bool fallback,
    1512             :                 const char *path,
    1513             :                 sd_bus_message_handler_t callback,
    1514             :                 void *userdata) {
    1515             : 
    1516             :         sd_bus_slot *s;
    1517             :         struct node *n;
    1518             :         int r;
    1519             : 
    1520           1 :         assert_return(bus, -EINVAL);
    1521           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    1522           1 :         assert_return(callback, -EINVAL);
    1523           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    1524             : 
    1525           1 :         n = bus_node_allocate(bus, path);
    1526           1 :         if (!n)
    1527           0 :                 return -ENOMEM;
    1528             : 
    1529           1 :         s = bus_slot_allocate(bus, !slot, BUS_NODE_CALLBACK, sizeof(struct node_callback), userdata);
    1530           1 :         if (!s) {
    1531           0 :                 r = -ENOMEM;
    1532           0 :                 goto fail;
    1533             :         }
    1534             : 
    1535           1 :         s->node_callback.callback = callback;
    1536           1 :         s->node_callback.is_fallback = fallback;
    1537             : 
    1538           1 :         s->node_callback.node = n;
    1539           1 :         LIST_PREPEND(callbacks, n->callbacks, &s->node_callback);
    1540           1 :         bus->nodes_modified = true;
    1541             : 
    1542           1 :         if (slot)
    1543           0 :                 *slot = s;
    1544             : 
    1545           1 :         return 0;
    1546             : 
    1547             : fail:
    1548           0 :         sd_bus_slot_unref(s);
    1549           0 :         bus_node_gc(bus, n);
    1550             : 
    1551           0 :         return r;
    1552             : }
    1553             : 
    1554           0 : _public_ int sd_bus_add_object(
    1555             :                 sd_bus *bus,
    1556             :                 sd_bus_slot **slot,
    1557             :                 const char *path,
    1558             :                 sd_bus_message_handler_t callback,
    1559             :                 void *userdata) {
    1560             : 
    1561           0 :         return bus_add_object(bus, slot, false, path, callback, userdata);
    1562             : }
    1563             : 
    1564           1 : _public_ int sd_bus_add_fallback(
    1565             :                 sd_bus *bus,
    1566             :                 sd_bus_slot **slot,
    1567             :                 const char *prefix,
    1568             :                 sd_bus_message_handler_t callback,
    1569             :                 void *userdata) {
    1570             : 
    1571           1 :         return bus_add_object(bus, slot, true, prefix, callback, userdata);
    1572             : }
    1573             : 
    1574         121 : static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
    1575         121 :         const struct vtable_member *m = a;
    1576             :         uint8_t hash_key2[HASH_KEY_SIZE];
    1577             :         unsigned long ret;
    1578             : 
    1579         121 :         assert(m);
    1580             : 
    1581         121 :         ret = string_hash_func(m->path, hash_key);
    1582             : 
    1583             :         /* Use a slightly different hash key for the interface */
    1584         121 :         memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
    1585         121 :         hash_key2[0]++;
    1586         121 :         ret ^= string_hash_func(m->interface, hash_key2);
    1587             : 
    1588             :         /* And an even different one for the  member */
    1589         121 :         hash_key2[0]++;
    1590         121 :         ret ^= string_hash_func(m->member, hash_key2);
    1591             : 
    1592         121 :         return ret;
    1593             : }
    1594             : 
    1595          71 : static int vtable_member_compare_func(const void *a, const void *b) {
    1596          71 :         const struct vtable_member *x = a, *y = b;
    1597             :         int r;
    1598             : 
    1599          71 :         assert(x);
    1600          71 :         assert(y);
    1601             : 
    1602          71 :         r = strcmp(x->path, y->path);
    1603          71 :         if (r != 0)
    1604          10 :                 return r;
    1605             : 
    1606          61 :         r = strcmp(x->interface, y->interface);
    1607          61 :         if (r != 0)
    1608           9 :                 return r;
    1609             : 
    1610          52 :         return strcmp(x->member, y->member);
    1611             : }
    1612             : 
    1613             : static const struct hash_ops vtable_member_hash_ops = {
    1614             :         .hash = vtable_member_hash_func,
    1615             :         .compare = vtable_member_compare_func
    1616             : };
    1617             : 
    1618           3 : static int add_object_vtable_internal(
    1619             :                 sd_bus *bus,
    1620             :                 sd_bus_slot **slot,
    1621             :                 const char *path,
    1622             :                 const char *interface,
    1623             :                 const sd_bus_vtable *vtable,
    1624             :                 bool fallback,
    1625             :                 sd_bus_object_find_t find,
    1626             :                 void *userdata) {
    1627             : 
    1628           3 :         sd_bus_slot *s = NULL;
    1629           3 :         struct node_vtable *i, *existing = NULL;
    1630             :         const sd_bus_vtable *v;
    1631             :         struct node *n;
    1632             :         int r;
    1633             : 
    1634           3 :         assert_return(bus, -EINVAL);
    1635           3 :         assert_return(object_path_is_valid(path), -EINVAL);
    1636           3 :         assert_return(interface_name_is_valid(interface), -EINVAL);
    1637           3 :         assert_return(vtable, -EINVAL);
    1638           3 :         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
    1639           3 :         assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
    1640           3 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    1641           3 :         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
    1642             :                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
    1643             :                       !streq(interface, "org.freedesktop.DBus.Peer") &&
    1644             :                       !streq(interface, "org.freedesktop.DBus.ObjectManager"), -EINVAL);
    1645             : 
    1646           3 :         r = hashmap_ensure_allocated(&bus->vtable_methods, &vtable_member_hash_ops);
    1647           3 :         if (r < 0)
    1648           0 :                 return r;
    1649             : 
    1650           3 :         r = hashmap_ensure_allocated(&bus->vtable_properties, &vtable_member_hash_ops);
    1651           3 :         if (r < 0)
    1652           0 :                 return r;
    1653             : 
    1654           3 :         n = bus_node_allocate(bus, path);
    1655           3 :         if (!n)
    1656           0 :                 return -ENOMEM;
    1657             : 
    1658           4 :         LIST_FOREACH(vtables, i, n->vtables) {
    1659           1 :                 if (i->is_fallback != fallback) {
    1660           0 :                         r = -EPROTOTYPE;
    1661           0 :                         goto fail;
    1662             :                 }
    1663             : 
    1664           1 :                 if (streq(i->interface, interface)) {
    1665             : 
    1666           0 :                         if (i->vtable == vtable) {
    1667           0 :                                 r = -EEXIST;
    1668           0 :                                 goto fail;
    1669             :                         }
    1670             : 
    1671           0 :                         existing = i;
    1672             :                 }
    1673             :         }
    1674             : 
    1675           3 :         s = bus_slot_allocate(bus, !slot, BUS_NODE_VTABLE, sizeof(struct node_vtable), userdata);
    1676           3 :         if (!s) {
    1677           0 :                 r = -ENOMEM;
    1678           0 :                 goto fail;
    1679             :         }
    1680             : 
    1681           3 :         s->node_vtable.is_fallback = fallback;
    1682           3 :         s->node_vtable.vtable = vtable;
    1683           3 :         s->node_vtable.find = find;
    1684             : 
    1685           3 :         s->node_vtable.interface = strdup(interface);
    1686           3 :         if (!s->node_vtable.interface) {
    1687           0 :                 r = -ENOMEM;
    1688           0 :                 goto fail;
    1689             :         }
    1690             : 
    1691          29 :         for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
    1692             : 
    1693          26 :                 switch (v->type) {
    1694             : 
    1695             :                 case _SD_BUS_VTABLE_METHOD: {
    1696             :                         struct vtable_member *m;
    1697             : 
    1698          32 :                         if (!member_name_is_valid(v->x.method.member) ||
    1699          32 :                             !signature_is_valid(strempty(v->x.method.signature), false) ||
    1700          32 :                             !signature_is_valid(strempty(v->x.method.result), false) ||
    1701          34 :                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
    1702          16 :                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
    1703           0 :                                 r = -EINVAL;
    1704           0 :                                 goto fail;
    1705             :                         }
    1706             : 
    1707          16 :                         m = new0(struct vtable_member, 1);
    1708          16 :                         if (!m) {
    1709           0 :                                 r = -ENOMEM;
    1710           0 :                                 goto fail;
    1711             :                         }
    1712             : 
    1713          16 :                         m->parent = &s->node_vtable;
    1714          16 :                         m->path = n->path;
    1715          16 :                         m->interface = s->node_vtable.interface;
    1716          16 :                         m->member = v->x.method.member;
    1717          16 :                         m->vtable = v;
    1718             : 
    1719          16 :                         r = hashmap_put(bus->vtable_methods, m, m);
    1720          16 :                         if (r < 0) {
    1721           0 :                                 free(m);
    1722           0 :                                 goto fail;
    1723             :                         }
    1724             : 
    1725          16 :                         break;
    1726             :                 }
    1727             : 
    1728             :                 case _SD_BUS_VTABLE_WRITABLE_PROPERTY:
    1729             : 
    1730           6 :                         if (!(v->x.property.set || bus_type_is_basic(v->x.property.signature[0]))) {
    1731           0 :                                 r = -EINVAL;
    1732           0 :                                 goto fail;
    1733             :                         }
    1734             : 
    1735           6 :                         if (v->flags & SD_BUS_VTABLE_PROPERTY_CONST) {
    1736           0 :                                 r = -EINVAL;
    1737           0 :                                 goto fail;
    1738             :                         }
    1739             : 
    1740             :                         /* Fall through */
    1741             : 
    1742             :                 case _SD_BUS_VTABLE_PROPERTY: {
    1743             :                         struct vtable_member *m;
    1744             : 
    1745          20 :                         if (!member_name_is_valid(v->x.property.member) ||
    1746          20 :                             !signature_is_single(v->x.property.signature, false) ||
    1747          24 :                             !(v->x.property.get || bus_type_is_basic(v->x.property.signature[0]) || streq(v->x.property.signature, "as")) ||
    1748          20 :                             v->flags & SD_BUS_VTABLE_METHOD_NO_REPLY ||
    1749          20 :                             (!!(v->flags & SD_BUS_VTABLE_PROPERTY_CONST) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) + !!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) > 1 ||
    1750          10 :                             (v->flags & SD_BUS_VTABLE_UNPRIVILEGED && v->type == _SD_BUS_VTABLE_PROPERTY)) {
    1751           0 :                                 r = -EINVAL;
    1752           0 :                                 goto fail;
    1753             :                         }
    1754             : 
    1755          10 :                         m = new0(struct vtable_member, 1);
    1756          10 :                         if (!m) {
    1757           0 :                                 r = -ENOMEM;
    1758           0 :                                 goto fail;
    1759             :                         }
    1760             : 
    1761          10 :                         m->parent = &s->node_vtable;
    1762          10 :                         m->path = n->path;
    1763          10 :                         m->interface = s->node_vtable.interface;
    1764          10 :                         m->member = v->x.property.member;
    1765          10 :                         m->vtable = v;
    1766             : 
    1767          10 :                         r = hashmap_put(bus->vtable_properties, m, m);
    1768          10 :                         if (r < 0) {
    1769           0 :                                 free(m);
    1770           0 :                                 goto fail;
    1771             :                         }
    1772             : 
    1773          10 :                         break;
    1774             :                 }
    1775             : 
    1776             :                 case _SD_BUS_VTABLE_SIGNAL:
    1777             : 
    1778           0 :                         if (!member_name_is_valid(v->x.signal.member) ||
    1779           0 :                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
    1780           0 :                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
    1781           0 :                                 r = -EINVAL;
    1782           0 :                                 goto fail;
    1783             :                         }
    1784             : 
    1785           0 :                         break;
    1786             : 
    1787             :                 default:
    1788           0 :                         r = -EINVAL;
    1789           0 :                         goto fail;
    1790             :                 }
    1791             :         }
    1792             : 
    1793           3 :         s->node_vtable.node = n;
    1794           3 :         LIST_INSERT_AFTER(vtables, n->vtables, existing, &s->node_vtable);
    1795           3 :         bus->nodes_modified = true;
    1796             : 
    1797           3 :         if (slot)
    1798           0 :                 *slot = s;
    1799             : 
    1800           3 :         return 0;
    1801             : 
    1802             : fail:
    1803           0 :         sd_bus_slot_unref(s);
    1804           0 :         bus_node_gc(bus, n);
    1805             : 
    1806           0 :         return r;
    1807             : }
    1808             : 
    1809           2 : _public_ int sd_bus_add_object_vtable(
    1810             :                 sd_bus *bus,
    1811             :                 sd_bus_slot **slot,
    1812             :                 const char *path,
    1813             :                 const char *interface,
    1814             :                 const sd_bus_vtable *vtable,
    1815             :                 void *userdata) {
    1816             : 
    1817           2 :         return add_object_vtable_internal(bus, slot, path, interface, vtable, false, NULL, userdata);
    1818             : }
    1819             : 
    1820           1 : _public_ int sd_bus_add_fallback_vtable(
    1821             :                 sd_bus *bus,
    1822             :                 sd_bus_slot **slot,
    1823             :                 const char *prefix,
    1824             :                 const char *interface,
    1825             :                 const sd_bus_vtable *vtable,
    1826             :                 sd_bus_object_find_t find,
    1827             :                 void *userdata) {
    1828             : 
    1829           1 :         return add_object_vtable_internal(bus, slot, prefix, interface, vtable, true, find, userdata);
    1830             : }
    1831             : 
    1832           2 : _public_ int sd_bus_add_node_enumerator(
    1833             :                 sd_bus *bus,
    1834             :                 sd_bus_slot **slot,
    1835             :                 const char *path,
    1836             :                 sd_bus_node_enumerator_t callback,
    1837             :                 void *userdata) {
    1838             : 
    1839             :         sd_bus_slot *s;
    1840             :         struct node *n;
    1841             :         int r;
    1842             : 
    1843           2 :         assert_return(bus, -EINVAL);
    1844           2 :         assert_return(object_path_is_valid(path), -EINVAL);
    1845           2 :         assert_return(callback, -EINVAL);
    1846           2 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    1847             : 
    1848           2 :         n = bus_node_allocate(bus, path);
    1849           2 :         if (!n)
    1850           0 :                 return -ENOMEM;
    1851             : 
    1852           2 :         s = bus_slot_allocate(bus, !slot, BUS_NODE_ENUMERATOR, sizeof(struct node_enumerator), userdata);
    1853           2 :         if (!s) {
    1854           0 :                 r = -ENOMEM;
    1855           0 :                 goto fail;
    1856             :         }
    1857             : 
    1858           2 :         s->node_enumerator.callback = callback;
    1859             : 
    1860           2 :         s->node_enumerator.node = n;
    1861           2 :         LIST_PREPEND(enumerators, n->enumerators, &s->node_enumerator);
    1862           2 :         bus->nodes_modified = true;
    1863             : 
    1864           2 :         if (slot)
    1865           0 :                 *slot = s;
    1866             : 
    1867           2 :         return 0;
    1868             : 
    1869             : fail:
    1870           0 :         sd_bus_slot_unref(s);
    1871           0 :         bus_node_gc(bus, n);
    1872             : 
    1873           0 :         return r;
    1874             : }
    1875             : 
    1876           4 : static int emit_properties_changed_on_interface(
    1877             :                 sd_bus *bus,
    1878             :                 const char *prefix,
    1879             :                 const char *path,
    1880             :                 const char *interface,
    1881             :                 bool require_fallback,
    1882             :                 bool *found_interface,
    1883             :                 char **names) {
    1884             : 
    1885           8 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    1886           8 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
    1887           4 :         bool has_invalidating = false, has_changing = false;
    1888           4 :         struct vtable_member key = {};
    1889             :         struct node_vtable *c;
    1890             :         struct node *n;
    1891             :         char **property;
    1892           4 :         void *u = NULL;
    1893             :         int r;
    1894             : 
    1895           4 :         assert(bus);
    1896           4 :         assert(prefix);
    1897           4 :         assert(path);
    1898           4 :         assert(interface);
    1899           4 :         assert(found_interface);
    1900             : 
    1901           4 :         n = hashmap_get(bus->nodes, prefix);
    1902           4 :         if (!n)
    1903           0 :                 return 0;
    1904             : 
    1905           4 :         r = sd_bus_message_new_signal(bus, &m, path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
    1906           4 :         if (r < 0)
    1907           0 :                 return r;
    1908             : 
    1909           4 :         r = sd_bus_message_append(m, "s", interface);
    1910           4 :         if (r < 0)
    1911           0 :                 return r;
    1912             : 
    1913           4 :         r = sd_bus_message_open_container(m, 'a', "{sv}");
    1914           4 :         if (r < 0)
    1915           0 :                 return r;
    1916             : 
    1917           4 :         key.path = prefix;
    1918           4 :         key.interface = interface;
    1919             : 
    1920           6 :         LIST_FOREACH(vtables, c, n->vtables) {
    1921           2 :                 if (require_fallback && !c->is_fallback)
    1922           0 :                         continue;
    1923             : 
    1924           2 :                 if (!streq(c->interface, interface))
    1925           0 :                         continue;
    1926             : 
    1927           2 :                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
    1928           2 :                 if (r < 0)
    1929           0 :                         return r;
    1930           2 :                 if (bus->nodes_modified)
    1931           0 :                         return 0;
    1932           2 :                 if (r == 0)
    1933           0 :                         continue;
    1934             : 
    1935           2 :                 *found_interface = true;
    1936             : 
    1937           2 :                 if (names) {
    1938             :                         /* If the caller specified a list of
    1939             :                          * properties we include exactly those in the
    1940             :                          * PropertiesChanged message */
    1941             : 
    1942           2 :                         STRV_FOREACH(property, names) {
    1943             :                                 struct vtable_member *v;
    1944             : 
    1945           1 :                                 assert_return(member_name_is_valid(*property), -EINVAL);
    1946             : 
    1947           1 :                                 key.member = *property;
    1948           1 :                                 v = hashmap_get(bus->vtable_properties, &key);
    1949           1 :                                 if (!v)
    1950           0 :                                         return -ENOENT;
    1951             : 
    1952             :                                 /* If there are two vtables for the same
    1953             :                                  * interface, let's handle this property when
    1954             :                                  * we come to that vtable. */
    1955           1 :                                 if (c != v->parent)
    1956           0 :                                         continue;
    1957             : 
    1958           1 :                                 assert_return(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ||
    1959             :                                               v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION, -EDOM);
    1960             : 
    1961           1 :                                 assert_return(!(v->vtable->flags & SD_BUS_VTABLE_HIDDEN), -EDOM);
    1962             : 
    1963           1 :                                 if (v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
    1964           0 :                                         has_invalidating = true;
    1965           0 :                                         continue;
    1966             :                                 }
    1967             : 
    1968           1 :                                 has_changing = true;
    1969             : 
    1970           1 :                                 r = vtable_append_one_property(bus, m, m->path, c, v->vtable, u, &error);
    1971           1 :                                 if (r < 0)
    1972           0 :                                         return r;
    1973           1 :                                 if (bus->nodes_modified)
    1974           0 :                                         return 0;
    1975             :                         }
    1976             :                 } else {
    1977             :                         const sd_bus_vtable *v;
    1978             : 
    1979             :                         /* If the caller specified no properties list
    1980             :                          * we include all properties that are marked
    1981             :                          * as changing in the message. */
    1982             : 
    1983           7 :                         for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
    1984           6 :                                 if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
    1985           2 :                                         continue;
    1986             : 
    1987           4 :                                 if (v->flags & SD_BUS_VTABLE_HIDDEN)
    1988           0 :                                         continue;
    1989             : 
    1990           4 :                                 if (v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) {
    1991           1 :                                         has_invalidating = true;
    1992           1 :                                         continue;
    1993             :                                 }
    1994             : 
    1995           3 :                                 if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
    1996           2 :                                         continue;
    1997             : 
    1998           1 :                                 has_changing = true;
    1999             : 
    2000           1 :                                 r = vtable_append_one_property(bus, m, m->path, c, v, u, &error);
    2001           1 :                                 if (r < 0)
    2002           0 :                                         return r;
    2003           1 :                                 if (bus->nodes_modified)
    2004           0 :                                         return 0;
    2005             :                         }
    2006             :                 }
    2007             :         }
    2008             : 
    2009           4 :         if (!has_invalidating && !has_changing)
    2010           2 :                 return 0;
    2011             : 
    2012           2 :         r = sd_bus_message_close_container(m);
    2013           2 :         if (r < 0)
    2014           0 :                 return r;
    2015             : 
    2016           2 :         r = sd_bus_message_open_container(m, 'a', "s");
    2017           2 :         if (r < 0)
    2018           0 :                 return r;
    2019             : 
    2020           2 :         if (has_invalidating) {
    2021           2 :                 LIST_FOREACH(vtables, c, n->vtables) {
    2022           1 :                         if (require_fallback && !c->is_fallback)
    2023           0 :                                 continue;
    2024             : 
    2025           1 :                         if (!streq(c->interface, interface))
    2026           0 :                                 continue;
    2027             : 
    2028           1 :                         r = node_vtable_get_userdata(bus, path, c, &u, &error);
    2029           1 :                         if (r < 0)
    2030           0 :                                 return r;
    2031           1 :                         if (bus->nodes_modified)
    2032           0 :                                 return 0;
    2033           1 :                         if (r == 0)
    2034           0 :                                 continue;
    2035             : 
    2036           1 :                         if (names) {
    2037           0 :                                 STRV_FOREACH(property, names) {
    2038             :                                         struct vtable_member *v;
    2039             : 
    2040           0 :                                         key.member = *property;
    2041           0 :                                         assert_se(v = hashmap_get(bus->vtable_properties, &key));
    2042           0 :                                         assert(c == v->parent);
    2043             : 
    2044           0 :                                         if (!(v->vtable->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
    2045           0 :                                                 continue;
    2046             : 
    2047           0 :                                         r = sd_bus_message_append(m, "s", *property);
    2048           0 :                                         if (r < 0)
    2049           0 :                                                 return r;
    2050             :                                 }
    2051             :                         } else {
    2052             :                                 const sd_bus_vtable *v;
    2053             : 
    2054           7 :                                 for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
    2055           6 :                                         if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
    2056           2 :                                                 continue;
    2057             : 
    2058           4 :                                         if (v->flags & SD_BUS_VTABLE_HIDDEN)
    2059           0 :                                                 continue;
    2060             : 
    2061           4 :                                         if (!(v->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION))
    2062           3 :                                                 continue;
    2063             : 
    2064           1 :                                         r = sd_bus_message_append(m, "s", v->x.property.member);
    2065           1 :                                         if (r < 0)
    2066           0 :                                                 return r;
    2067             :                                 }
    2068             :                         }
    2069             :                 }
    2070             :         }
    2071             : 
    2072           2 :         r = sd_bus_message_close_container(m);
    2073           2 :         if (r < 0)
    2074           0 :                 return r;
    2075             : 
    2076           2 :         r = sd_bus_send(bus, m, NULL);
    2077           2 :         if (r < 0)
    2078           0 :                 return r;
    2079             : 
    2080           2 :         return 1;
    2081             : }
    2082             : 
    2083           2 : _public_ int sd_bus_emit_properties_changed_strv(
    2084             :                 sd_bus *bus,
    2085             :                 const char *path,
    2086             :                 const char *interface,
    2087             :                 char **names) {
    2088             : 
    2089           4 :         BUS_DONT_DESTROY(bus);
    2090           2 :         bool found_interface = false;
    2091             :         char *prefix;
    2092             :         int r;
    2093             : 
    2094           2 :         assert_return(bus, -EINVAL);
    2095           2 :         assert_return(object_path_is_valid(path), -EINVAL);
    2096           2 :         assert_return(interface_name_is_valid(interface), -EINVAL);
    2097           2 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2098             : 
    2099           2 :         if (!BUS_IS_OPEN(bus->state))
    2100           0 :                 return -ENOTCONN;
    2101             : 
    2102             :         /* A non-NULL but empty names list means nothing needs to be
    2103             :            generated. A NULL list OTOH indicates that all properties
    2104             :            that are set to EMITS_CHANGE or EMITS_INVALIDATION shall be
    2105             :            included in the PropertiesChanged message. */
    2106           2 :         if (names && names[0] == NULL)
    2107           0 :                 return 0;
    2108             : 
    2109             :         do {
    2110           2 :                 bus->nodes_modified = false;
    2111             : 
    2112           2 :                 r = emit_properties_changed_on_interface(bus, path, path, interface, false, &found_interface, names);
    2113           2 :                 if (r != 0)
    2114           0 :                         return r;
    2115           2 :                 if (bus->nodes_modified)
    2116           0 :                         continue;
    2117             : 
    2118           2 :                 prefix = alloca(strlen(path) + 1);
    2119           2 :                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
    2120           2 :                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
    2121           2 :                         if (r != 0)
    2122           2 :                                 return r;
    2123           0 :                         if (bus->nodes_modified)
    2124           0 :                                 break;
    2125             :                 }
    2126             : 
    2127           0 :         } while (bus->nodes_modified);
    2128             : 
    2129           0 :         return found_interface ? 0 : -ENOENT;
    2130             : }
    2131             : 
    2132           1 : _public_ int sd_bus_emit_properties_changed(
    2133             :                 sd_bus *bus,
    2134             :                 const char *path,
    2135             :                 const char *interface,
    2136             :                 const char *name, ...)  {
    2137             : 
    2138             :         char **names;
    2139             : 
    2140           1 :         assert_return(bus, -EINVAL);
    2141           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2142           1 :         assert_return(interface_name_is_valid(interface), -EINVAL);
    2143           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2144             : 
    2145           1 :         if (!BUS_IS_OPEN(bus->state))
    2146           0 :                 return -ENOTCONN;
    2147             : 
    2148           1 :         if (!name)
    2149           0 :                 return 0;
    2150             : 
    2151           1 :         names = strv_from_stdarg_alloca(name);
    2152             : 
    2153           1 :         return sd_bus_emit_properties_changed_strv(bus, path, interface, names);
    2154             : }
    2155             : 
    2156           4 : static int object_added_append_all_prefix(
    2157             :                 sd_bus *bus,
    2158             :                 sd_bus_message *m,
    2159             :                 Set *s,
    2160             :                 const char *prefix,
    2161             :                 const char *path,
    2162             :                 bool require_fallback) {
    2163             : 
    2164           4 :         const char *previous_interface = NULL;
    2165             :         struct node_vtable *c;
    2166             :         struct node *n;
    2167             :         int r;
    2168             : 
    2169           4 :         assert(bus);
    2170           4 :         assert(m);
    2171           4 :         assert(s);
    2172           4 :         assert(prefix);
    2173           4 :         assert(path);
    2174             : 
    2175           4 :         n = hashmap_get(bus->nodes, prefix);
    2176           4 :         if (!n)
    2177           1 :                 return 0;
    2178             : 
    2179           4 :         LIST_FOREACH(vtables, c, n->vtables) {
    2180           2 :                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    2181           1 :                 void *u = NULL;
    2182             : 
    2183           1 :                 if (require_fallback && !c->is_fallback)
    2184           0 :                         continue;
    2185             : 
    2186           1 :                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
    2187           1 :                 if (r < 0)
    2188           0 :                         return r;
    2189           1 :                 if (bus->nodes_modified)
    2190           0 :                         return 0;
    2191           1 :                 if (r == 0)
    2192           0 :                         continue;
    2193             : 
    2194           1 :                 if (!streq_ptr(c->interface, previous_interface)) {
    2195             :                         /* If a child-node already handled this interface, we
    2196             :                          * skip it on any of its parents. The child vtables
    2197             :                          * always fully override any conflicting vtables of
    2198             :                          * any parent node. */
    2199           1 :                         if (set_get(s, c->interface))
    2200           0 :                                 continue;
    2201             : 
    2202           1 :                         r = set_put(s, c->interface);
    2203           1 :                         if (r < 0)
    2204           0 :                                 return r;
    2205             : 
    2206           1 :                         if (previous_interface) {
    2207           0 :                                 r = sd_bus_message_close_container(m);
    2208           0 :                                 if (r < 0)
    2209           0 :                                         return r;
    2210           0 :                                 r = sd_bus_message_close_container(m);
    2211           0 :                                 if (r < 0)
    2212           0 :                                         return r;
    2213             :                         }
    2214             : 
    2215           1 :                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
    2216           1 :                         if (r < 0)
    2217           0 :                                 return r;
    2218           1 :                         r = sd_bus_message_append(m, "s", c->interface);
    2219           1 :                         if (r < 0)
    2220           0 :                                 return r;
    2221           1 :                         r = sd_bus_message_open_container(m, 'a', "{sv}");
    2222           1 :                         if (r < 0)
    2223           0 :                                 return r;
    2224             : 
    2225           1 :                         previous_interface = c->interface;
    2226             :                 }
    2227             : 
    2228           1 :                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
    2229           1 :                 if (r < 0)
    2230           0 :                         return r;
    2231           1 :                 if (bus->nodes_modified)
    2232           0 :                         return 0;
    2233             :         }
    2234             : 
    2235           3 :         if (previous_interface) {
    2236           1 :                 r = sd_bus_message_close_container(m);
    2237           1 :                 if (r < 0)
    2238           0 :                         return r;
    2239           1 :                 r = sd_bus_message_close_container(m);
    2240           1 :                 if (r < 0)
    2241           0 :                         return r;
    2242             :         }
    2243             : 
    2244           3 :         return 0;
    2245             : }
    2246             : 
    2247           1 : static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
    2248           2 :         _cleanup_set_free_ Set *s = NULL;
    2249             :         char *prefix;
    2250             :         int r;
    2251             : 
    2252           1 :         assert(bus);
    2253           1 :         assert(m);
    2254           1 :         assert(path);
    2255             : 
    2256             :         /*
    2257             :          * This appends all interfaces registered on path @path. We first add
    2258             :          * the builtin interfaces, which are always available and handled by
    2259             :          * sd-bus. Then, we add all interfaces registered on the exact node,
    2260             :          * followed by all fallback interfaces registered on any parent prefix.
    2261             :          *
    2262             :          * If an interface is registered multiple times on the same node with
    2263             :          * different vtables, we merge all the properties across all vtables.
    2264             :          * However, if a child node has the same interface registered as one of
    2265             :          * its parent nodes has as fallback, we make the child overwrite the
    2266             :          * parent instead of extending it. Therefore, we keep a "Set" of all
    2267             :          * handled interfaces during parent traversal, so we skip interfaces on
    2268             :          * a parent that were overwritten by a child.
    2269             :          */
    2270             : 
    2271           1 :         s = set_new(&string_hash_ops);
    2272           1 :         if (!s)
    2273           0 :                 return -ENOMEM;
    2274             : 
    2275           1 :         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Peer", 0);
    2276           1 :         if (r < 0)
    2277           0 :                 return r;
    2278           1 :         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Introspectable", 0);
    2279           1 :         if (r < 0)
    2280           0 :                 return r;
    2281           1 :         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.Properties", 0);
    2282           1 :         if (r < 0)
    2283           0 :                 return r;
    2284           1 :         r = sd_bus_message_append(m, "{sa{sv}}", "org.freedesktop.DBus.ObjectManager", 0);
    2285           1 :         if (r < 0)
    2286           0 :                 return r;
    2287             : 
    2288           1 :         r = object_added_append_all_prefix(bus, m, s, path, path, false);
    2289           1 :         if (r < 0)
    2290           0 :                 return r;
    2291           1 :         if (bus->nodes_modified)
    2292           0 :                 return 0;
    2293             : 
    2294           1 :         prefix = alloca(strlen(path) + 1);
    2295           4 :         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
    2296           3 :                 r = object_added_append_all_prefix(bus, m, s, prefix, path, true);
    2297           3 :                 if (r < 0)
    2298           0 :                         return r;
    2299           3 :                 if (bus->nodes_modified)
    2300           0 :                         return 0;
    2301             :         }
    2302             : 
    2303           1 :         return 0;
    2304             : }
    2305             : 
    2306           1 : _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) {
    2307           2 :         BUS_DONT_DESTROY(bus);
    2308             : 
    2309           2 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
    2310             :         struct node *object_manager;
    2311             :         int r;
    2312             : 
    2313             :         /*
    2314             :          * This emits an InterfacesAdded signal on the given path, by iterating
    2315             :          * all registered vtables and fallback vtables on the path. All
    2316             :          * properties are queried and included in the signal.
    2317             :          * This call is equivalent to sd_bus_emit_interfaces_added() with an
    2318             :          * explicit list of registered interfaces. However, unlike
    2319             :          * interfaces_added(), this call can figure out the list of supported
    2320             :          * interfaces itself. Furthermore, it properly adds the builtin
    2321             :          * org.freedesktop.DBus.* interfaces.
    2322             :          */
    2323             : 
    2324           1 :         assert_return(bus, -EINVAL);
    2325           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2326           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2327             : 
    2328           1 :         if (!BUS_IS_OPEN(bus->state))
    2329           0 :                 return -ENOTCONN;
    2330             : 
    2331           1 :         r = bus_find_parent_object_manager(bus, &object_manager, path);
    2332           1 :         if (r < 0)
    2333           0 :                 return r;
    2334           1 :         if (r == 0)
    2335           0 :                 return -ESRCH;
    2336             : 
    2337             :         do {
    2338           1 :                 bus->nodes_modified = false;
    2339           1 :                 m = sd_bus_message_unref(m);
    2340             : 
    2341           1 :                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
    2342           1 :                 if (r < 0)
    2343           0 :                         return r;
    2344             : 
    2345           1 :                 r = sd_bus_message_append_basic(m, 'o', path);
    2346           1 :                 if (r < 0)
    2347           0 :                         return r;
    2348             : 
    2349           1 :                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
    2350           1 :                 if (r < 0)
    2351           0 :                         return r;
    2352             : 
    2353           1 :                 r = object_added_append_all(bus, m, path);
    2354           1 :                 if (r < 0)
    2355           0 :                         return r;
    2356             : 
    2357           1 :                 if (bus->nodes_modified)
    2358           0 :                         continue;
    2359             : 
    2360           1 :                 r = sd_bus_message_close_container(m);
    2361           1 :                 if (r < 0)
    2362           0 :                         return r;
    2363             : 
    2364           1 :         } while (bus->nodes_modified);
    2365             : 
    2366           1 :         return sd_bus_send(bus, m, NULL);
    2367             : }
    2368             : 
    2369           4 : static int object_removed_append_all_prefix(
    2370             :                 sd_bus *bus,
    2371             :                 sd_bus_message *m,
    2372             :                 Set *s,
    2373             :                 const char *prefix,
    2374             :                 const char *path,
    2375             :                 bool require_fallback) {
    2376             : 
    2377           4 :         const char *previous_interface = NULL;
    2378             :         struct node_vtable *c;
    2379             :         struct node *n;
    2380             :         int r;
    2381             : 
    2382           4 :         assert(bus);
    2383           4 :         assert(m);
    2384           4 :         assert(s);
    2385           4 :         assert(prefix);
    2386           4 :         assert(path);
    2387             : 
    2388           4 :         n = hashmap_get(bus->nodes, prefix);
    2389           4 :         if (!n)
    2390           1 :                 return 0;
    2391             : 
    2392           4 :         LIST_FOREACH(vtables, c, n->vtables) {
    2393           2 :                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    2394           1 :                 void *u = NULL;
    2395             : 
    2396           1 :                 if (require_fallback && !c->is_fallback)
    2397           0 :                         continue;
    2398           1 :                 if (streq_ptr(c->interface, previous_interface))
    2399           0 :                         continue;
    2400             : 
    2401             :                 /* If a child-node already handled this interface, we
    2402             :                  * skip it on any of its parents. The child vtables
    2403             :                  * always fully override any conflicting vtables of
    2404             :                  * any parent node. */
    2405           1 :                 if (set_get(s, c->interface))
    2406           0 :                         continue;
    2407             : 
    2408           1 :                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
    2409           1 :                 if (r < 0)
    2410           0 :                         return r;
    2411           1 :                 if (bus->nodes_modified)
    2412           0 :                         return 0;
    2413           1 :                 if (r == 0)
    2414           0 :                         continue;
    2415             : 
    2416           1 :                 r = set_put(s, c->interface);
    2417           1 :                 if (r < 0)
    2418           0 :                         return r;
    2419             : 
    2420           1 :                 r = sd_bus_message_append(m, "s", c->interface);
    2421           1 :                 if (r < 0)
    2422           0 :                         return r;
    2423             : 
    2424           1 :                 previous_interface = c->interface;
    2425             :         }
    2426             : 
    2427           3 :         return 0;
    2428             : }
    2429             : 
    2430           1 : static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
    2431           2 :         _cleanup_set_free_ Set *s = NULL;
    2432             :         char *prefix;
    2433             :         int r;
    2434             : 
    2435           1 :         assert(bus);
    2436           1 :         assert(m);
    2437           1 :         assert(path);
    2438             : 
    2439             :         /* see sd_bus_emit_object_added() for details */
    2440             : 
    2441           1 :         s = set_new(&string_hash_ops);
    2442           1 :         if (!s)
    2443           0 :                 return -ENOMEM;
    2444             : 
    2445           1 :         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Peer");
    2446           1 :         if (r < 0)
    2447           0 :                 return r;
    2448           1 :         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Introspectable");
    2449           1 :         if (r < 0)
    2450           0 :                 return r;
    2451           1 :         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.Properties");
    2452           1 :         if (r < 0)
    2453           0 :                 return r;
    2454           1 :         r = sd_bus_message_append(m, "s", "org.freedesktop.DBus.ObjectManager");
    2455           1 :         if (r < 0)
    2456           0 :                 return r;
    2457             : 
    2458           1 :         r = object_removed_append_all_prefix(bus, m, s, path, path, false);
    2459           1 :         if (r < 0)
    2460           0 :                 return r;
    2461           1 :         if (bus->nodes_modified)
    2462           0 :                 return 0;
    2463             : 
    2464           1 :         prefix = alloca(strlen(path) + 1);
    2465           4 :         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
    2466           3 :                 r = object_removed_append_all_prefix(bus, m, s, prefix, path, true);
    2467           3 :                 if (r < 0)
    2468           0 :                         return r;
    2469           3 :                 if (bus->nodes_modified)
    2470           0 :                         return 0;
    2471             :         }
    2472             : 
    2473           1 :         return 0;
    2474             : }
    2475             : 
    2476           1 : _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) {
    2477           2 :         BUS_DONT_DESTROY(bus);
    2478             : 
    2479           2 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
    2480             :         struct node *object_manager;
    2481             :         int r;
    2482             : 
    2483             :         /*
    2484             :          * This is like sd_bus_emit_object_added(), but emits an
    2485             :          * InterfacesRemoved signal on the given path. This only includes any
    2486             :          * registered interfaces but skips the properties. Note that this will
    2487             :          * call into the find() callbacks of any registered vtable. Therefore,
    2488             :          * you must call this function before destroying/unlinking your object.
    2489             :          * Otherwise, the list of interfaces will be incomplete. However, note
    2490             :          * that this will *NOT* call into any property callback. Therefore, the
    2491             :          * object might be in an "destructed" state, as long as we can find it.
    2492             :          */
    2493             : 
    2494           1 :         assert_return(bus, -EINVAL);
    2495           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2496           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2497             : 
    2498           1 :         if (!BUS_IS_OPEN(bus->state))
    2499           0 :                 return -ENOTCONN;
    2500             : 
    2501           1 :         r = bus_find_parent_object_manager(bus, &object_manager, path);
    2502           1 :         if (r < 0)
    2503           0 :                 return r;
    2504           1 :         if (r == 0)
    2505           0 :                 return -ESRCH;
    2506             : 
    2507             :         do {
    2508           1 :                 bus->nodes_modified = false;
    2509           1 :                 m = sd_bus_message_unref(m);
    2510             : 
    2511           1 :                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
    2512           1 :                 if (r < 0)
    2513           0 :                         return r;
    2514             : 
    2515           1 :                 r = sd_bus_message_append_basic(m, 'o', path);
    2516           1 :                 if (r < 0)
    2517           0 :                         return r;
    2518             : 
    2519           1 :                 r = sd_bus_message_open_container(m, 'a', "s");
    2520           1 :                 if (r < 0)
    2521           0 :                         return r;
    2522             : 
    2523           1 :                 r = object_removed_append_all(bus, m, path);
    2524           1 :                 if (r < 0)
    2525           0 :                         return r;
    2526             : 
    2527           1 :                 if (bus->nodes_modified)
    2528           0 :                         continue;
    2529             : 
    2530           1 :                 r = sd_bus_message_close_container(m);
    2531           1 :                 if (r < 0)
    2532           0 :                         return r;
    2533             : 
    2534           1 :         } while (bus->nodes_modified);
    2535             : 
    2536           1 :         return sd_bus_send(bus, m, NULL);
    2537             : }
    2538             : 
    2539           3 : static int interfaces_added_append_one_prefix(
    2540             :                 sd_bus *bus,
    2541             :                 sd_bus_message *m,
    2542             :                 const char *prefix,
    2543             :                 const char *path,
    2544             :                 const char *interface,
    2545             :                 bool require_fallback) {
    2546             : 
    2547           6 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
    2548           3 :         bool found_interface = false;
    2549             :         struct node_vtable *c;
    2550             :         struct node *n;
    2551           3 :         void *u = NULL;
    2552             :         int r;
    2553             : 
    2554           3 :         assert(bus);
    2555           3 :         assert(m);
    2556           3 :         assert(prefix);
    2557           3 :         assert(path);
    2558           3 :         assert(interface);
    2559             : 
    2560           3 :         n = hashmap_get(bus->nodes, prefix);
    2561           3 :         if (!n)
    2562           1 :                 return 0;
    2563             : 
    2564           3 :         LIST_FOREACH(vtables, c, n->vtables) {
    2565           1 :                 if (require_fallback && !c->is_fallback)
    2566           0 :                         continue;
    2567             : 
    2568           1 :                 if (!streq(c->interface, interface))
    2569           0 :                         continue;
    2570             : 
    2571           1 :                 r = node_vtable_get_userdata(bus, path, c, &u, &error);
    2572           1 :                 if (r < 0)
    2573           0 :                         return r;
    2574           1 :                 if (bus->nodes_modified)
    2575           0 :                         return 0;
    2576           1 :                 if (r == 0)
    2577           0 :                         continue;
    2578             : 
    2579           1 :                 if (!found_interface) {
    2580           1 :                         r = sd_bus_message_append_basic(m, 's', interface);
    2581           1 :                         if (r < 0)
    2582           0 :                                 return r;
    2583             : 
    2584           1 :                         r = sd_bus_message_open_container(m, 'a', "{sv}");
    2585           1 :                         if (r < 0)
    2586           0 :                                 return r;
    2587             : 
    2588           1 :                         found_interface = true;
    2589             :                 }
    2590             : 
    2591           1 :                 r = vtable_append_all_properties(bus, m, path, c, u, &error);
    2592           1 :                 if (r < 0)
    2593           0 :                         return r;
    2594           1 :                 if (bus->nodes_modified)
    2595           0 :                         return 0;
    2596             :         }
    2597             : 
    2598           2 :         if (found_interface) {
    2599           1 :                 r = sd_bus_message_close_container(m);
    2600           1 :                 if (r < 0)
    2601           0 :                         return r;
    2602             :         }
    2603             : 
    2604           2 :         return found_interface;
    2605             : }
    2606             : 
    2607           1 : static int interfaces_added_append_one(
    2608             :                 sd_bus *bus,
    2609             :                 sd_bus_message *m,
    2610             :                 const char *path,
    2611             :                 const char *interface) {
    2612             : 
    2613             :         char *prefix;
    2614             :         int r;
    2615             : 
    2616           1 :         assert(bus);
    2617           1 :         assert(m);
    2618           1 :         assert(path);
    2619           1 :         assert(interface);
    2620             : 
    2621           1 :         r = interfaces_added_append_one_prefix(bus, m, path, path, interface, false);
    2622           1 :         if (r != 0)
    2623           0 :                 return r;
    2624           1 :         if (bus->nodes_modified)
    2625           0 :                 return 0;
    2626             : 
    2627           1 :         prefix = alloca(strlen(path) + 1);
    2628           2 :         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
    2629           2 :                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
    2630           2 :                 if (r != 0)
    2631           1 :                         return r;
    2632           1 :                 if (bus->nodes_modified)
    2633           0 :                         return 0;
    2634             :         }
    2635             : 
    2636           0 :         return -ENOENT;
    2637             : }
    2638             : 
    2639           1 : _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) {
    2640           2 :         BUS_DONT_DESTROY(bus);
    2641             : 
    2642           2 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
    2643             :         struct node *object_manager;
    2644             :         char **i;
    2645             :         int r;
    2646             : 
    2647           1 :         assert_return(bus, -EINVAL);
    2648           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2649           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2650             : 
    2651           1 :         if (!BUS_IS_OPEN(bus->state))
    2652           0 :                 return -ENOTCONN;
    2653             : 
    2654           1 :         if (strv_isempty(interfaces))
    2655           0 :                 return 0;
    2656             : 
    2657           1 :         r = bus_find_parent_object_manager(bus, &object_manager, path);
    2658           1 :         if (r < 0)
    2659           0 :                 return r;
    2660           1 :         if (r == 0)
    2661           0 :                 return -ESRCH;
    2662             : 
    2663             :         do {
    2664           1 :                 bus->nodes_modified = false;
    2665           1 :                 m = sd_bus_message_unref(m);
    2666             : 
    2667           1 :                 r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded");
    2668           1 :                 if (r < 0)
    2669           0 :                         return r;
    2670             : 
    2671           1 :                 r = sd_bus_message_append_basic(m, 'o', path);
    2672           1 :                 if (r < 0)
    2673           0 :                         return r;
    2674             : 
    2675           1 :                 r = sd_bus_message_open_container(m, 'a', "{sa{sv}}");
    2676           1 :                 if (r < 0)
    2677           0 :                         return r;
    2678             : 
    2679           2 :                 STRV_FOREACH(i, interfaces) {
    2680           1 :                         assert_return(interface_name_is_valid(*i), -EINVAL);
    2681             : 
    2682           1 :                         r = sd_bus_message_open_container(m, 'e', "sa{sv}");
    2683           1 :                         if (r < 0)
    2684           0 :                                 return r;
    2685             : 
    2686           1 :                         r = interfaces_added_append_one(bus, m, path, *i);
    2687           1 :                         if (r < 0)
    2688           0 :                                 return r;
    2689             : 
    2690           1 :                         if (bus->nodes_modified)
    2691           0 :                                 break;
    2692             : 
    2693           1 :                         r = sd_bus_message_close_container(m);
    2694           1 :                         if (r < 0)
    2695           0 :                                 return r;
    2696             :                 }
    2697             : 
    2698           1 :                 if (bus->nodes_modified)
    2699           0 :                         continue;
    2700             : 
    2701           1 :                 r = sd_bus_message_close_container(m);
    2702           1 :                 if (r < 0)
    2703           0 :                         return r;
    2704             : 
    2705           1 :         } while (bus->nodes_modified);
    2706             : 
    2707           1 :         return sd_bus_send(bus, m, NULL);
    2708             : }
    2709             : 
    2710           1 : _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) {
    2711             :         char **interfaces;
    2712             : 
    2713           1 :         assert_return(bus, -EINVAL);
    2714           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2715           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2716             : 
    2717           1 :         if (!BUS_IS_OPEN(bus->state))
    2718           0 :                 return -ENOTCONN;
    2719             : 
    2720           1 :         interfaces = strv_from_stdarg_alloca(interface);
    2721             : 
    2722           1 :         return sd_bus_emit_interfaces_added_strv(bus, path, interfaces);
    2723             : }
    2724             : 
    2725           1 : _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) {
    2726           2 :         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
    2727             :         struct node *object_manager;
    2728             :         int r;
    2729             : 
    2730           1 :         assert_return(bus, -EINVAL);
    2731           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2732           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2733             : 
    2734           1 :         if (!BUS_IS_OPEN(bus->state))
    2735           0 :                 return -ENOTCONN;
    2736             : 
    2737           1 :         if (strv_isempty(interfaces))
    2738           0 :                 return 0;
    2739             : 
    2740           1 :         r = bus_find_parent_object_manager(bus, &object_manager, path);
    2741           1 :         if (r < 0)
    2742           0 :                 return r;
    2743           1 :         if (r == 0)
    2744           0 :                 return -ESRCH;
    2745             : 
    2746           1 :         r = sd_bus_message_new_signal(bus, &m, object_manager->path, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved");
    2747           1 :         if (r < 0)
    2748           0 :                 return r;
    2749             : 
    2750           1 :         r = sd_bus_message_append_basic(m, 'o', path);
    2751           1 :         if (r < 0)
    2752           0 :                 return r;
    2753             : 
    2754           1 :         r = sd_bus_message_append_strv(m, interfaces);
    2755           1 :         if (r < 0)
    2756           0 :                 return r;
    2757             : 
    2758           1 :         return sd_bus_send(bus, m, NULL);
    2759             : }
    2760             : 
    2761           1 : _public_ int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) {
    2762             :         char **interfaces;
    2763             : 
    2764           1 :         assert_return(bus, -EINVAL);
    2765           1 :         assert_return(object_path_is_valid(path), -EINVAL);
    2766           1 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2767             : 
    2768           1 :         if (!BUS_IS_OPEN(bus->state))
    2769           0 :                 return -ENOTCONN;
    2770             : 
    2771           1 :         interfaces = strv_from_stdarg_alloca(interface);
    2772             : 
    2773           1 :         return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces);
    2774             : }
    2775             : 
    2776           2 : _public_ int sd_bus_add_object_manager(sd_bus *bus, sd_bus_slot **slot, const char *path) {
    2777             :         sd_bus_slot *s;
    2778             :         struct node *n;
    2779             :         int r;
    2780             : 
    2781           2 :         assert_return(bus, -EINVAL);
    2782           2 :         assert_return(object_path_is_valid(path), -EINVAL);
    2783           2 :         assert_return(!bus_pid_changed(bus), -ECHILD);
    2784             : 
    2785           2 :         n = bus_node_allocate(bus, path);
    2786           2 :         if (!n)
    2787           0 :                 return -ENOMEM;
    2788             : 
    2789           2 :         s = bus_slot_allocate(bus, !slot, BUS_NODE_OBJECT_MANAGER, sizeof(struct node_object_manager), NULL);
    2790           2 :         if (!s) {
    2791           0 :                 r = -ENOMEM;
    2792           0 :                 goto fail;
    2793             :         }
    2794             : 
    2795           2 :         s->node_object_manager.node = n;
    2796           2 :         LIST_PREPEND(object_managers, n->object_managers, &s->node_object_manager);
    2797           2 :         bus->nodes_modified = true;
    2798             : 
    2799           2 :         if (slot)
    2800           0 :                 *slot = s;
    2801             : 
    2802           2 :         return 0;
    2803             : 
    2804             : fail:
    2805           0 :         sd_bus_slot_unref(s);
    2806           0 :         bus_node_gc(bus, n);
    2807             : 
    2808           0 :         return r;
    2809             : }

Generated by: LCOV version 1.11