| File: | build-scan/../src/libsystemd/sd-bus/bus-track.c |
| Warning: | line 232, column 25 Potential leak of memory pointed to by 'n' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | /*** | |||
| 3 | ***/ | |||
| 4 | ||||
| 5 | #include "sd-bus.h" | |||
| 6 | ||||
| 7 | #include "alloc-util.h" | |||
| 8 | #include "bus-internal.h" | |||
| 9 | #include "bus-track.h" | |||
| 10 | #include "bus-util.h" | |||
| 11 | ||||
| 12 | struct track_item { | |||
| 13 | unsigned n_ref; | |||
| 14 | char *name; | |||
| 15 | sd_bus_slot *slot; | |||
| 16 | }; | |||
| 17 | ||||
| 18 | struct sd_bus_track { | |||
| 19 | unsigned n_ref; | |||
| 20 | unsigned n_adding; /* are we in the process of adding a new name? */ | |||
| 21 | sd_bus *bus; | |||
| 22 | sd_bus_track_handler_t handler; | |||
| 23 | void *userdata; | |||
| 24 | Hashmap *names; | |||
| 25 | LIST_FIELDS(sd_bus_track, queue)sd_bus_track *queue_next, *queue_prev; | |||
| 26 | Iterator iterator; | |||
| 27 | bool_Bool in_list:1; /* In bus->tracks? */ | |||
| 28 | bool_Bool in_queue:1; /* In bus->track_queue? */ | |||
| 29 | bool_Bool modified:1; | |||
| 30 | bool_Bool recursive:1; | |||
| 31 | sd_bus_destroy_t destroy_callback; | |||
| 32 | ||||
| 33 | LIST_FIELDS(sd_bus_track, tracks)sd_bus_track *tracks_next, *tracks_prev; | |||
| 34 | }; | |||
| 35 | ||||
| 36 | #define MATCH_FOR_NAME(name)({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) \ | |||
| 37 | strjoina("type='signal'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) | |||
| 38 | "sender='org.freedesktop.DBus'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) | |||
| 39 | "path='/org/freedesktop/DBus'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) | |||
| 40 | "interface='org.freedesktop.DBus'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) | |||
| 41 | "member='NameOwnerChanged'," \({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) | |||
| 42 | "arg0='", name, "'")({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }) | |||
| 43 | ||||
| 44 | static struct track_item* track_item_free(struct track_item *i) { | |||
| 45 | ||||
| 46 | if (!i) | |||
| 47 | return NULL((void*)0); | |||
| 48 | ||||
| 49 | sd_bus_slot_unref(i->slot); | |||
| 50 | free(i->name); | |||
| 51 | return mfree(i); | |||
| 52 | } | |||
| 53 | ||||
| 54 | DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free)static inline void track_item_freep(struct track_item* *p) { if (*p) track_item_free(*p); }; | |||
| 55 | ||||
| 56 | static void bus_track_add_to_queue(sd_bus_track *track) { | |||
| 57 | assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 57, __PRETTY_FUNCTION__); } while (0); | |||
| 58 | ||||
| 59 | /* Adds the bus track object to the queue of objects we should dispatch next, subject to a number of | |||
| 60 | * conditions. */ | |||
| 61 | ||||
| 62 | /* Already in the queue? */ | |||
| 63 | if (track->in_queue) | |||
| 64 | return; | |||
| 65 | ||||
| 66 | /* if we are currently in the process of adding a new name, then let's not enqueue this just yet, let's wait | |||
| 67 | * until the addition is complete. */ | |||
| 68 | if (track->n_adding > 0) | |||
| 69 | return; | |||
| 70 | ||||
| 71 | /* still referenced? */ | |||
| 72 | if (hashmap_size(track->names) > 0) | |||
| 73 | return; | |||
| 74 | ||||
| 75 | /* Nothing to call? */ | |||
| 76 | if (!track->handler) | |||
| 77 | return; | |||
| 78 | ||||
| 79 | /* Already closed? */ | |||
| 80 | if (!track->in_list) | |||
| 81 | return; | |||
| 82 | ||||
| 83 | LIST_PREPEND(queue, track->bus->track_queue, track)do { typeof(*(track->bus->track_queue)) **_head = & (track->bus->track_queue), *_item = (track); do { if (( __builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("_item"), "../src/libsystemd/sd-bus/bus-track.c", 83, __PRETTY_FUNCTION__ ); } while (0); if ((_item->queue_next = *_head)) _item-> queue_next->queue_prev = _item; _item->queue_prev = ((void *)0); *_head = _item; } while (0); | |||
| 84 | track->in_queue = true1; | |||
| 85 | } | |||
| 86 | ||||
| 87 | static void bus_track_remove_from_queue(sd_bus_track *track) { | |||
| 88 | assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 88, __PRETTY_FUNCTION__); } while (0); | |||
| 89 | ||||
| 90 | if (!track->in_queue) | |||
| 91 | return; | |||
| 92 | ||||
| 93 | LIST_REMOVE(queue, track->bus->track_queue, track)do { typeof(*(track->bus->track_queue)) **_head = & (track->bus->track_queue), *_item = (track); do { if (( __builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("_item"), "../src/libsystemd/sd-bus/bus-track.c", 93, __PRETTY_FUNCTION__ ); } while (0); if (_item->queue_next) _item->queue_next ->queue_prev = _item->queue_prev; if (_item->queue_prev ) _item->queue_prev->queue_next = _item->queue_next; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/libsystemd/sd-bus/bus-track.c", 93, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->queue_next; } _item->queue_next = _item->queue_prev = ((void*)0); } while (0); | |||
| 94 | track->in_queue = false0; | |||
| 95 | } | |||
| 96 | ||||
| 97 | static int bus_track_remove_name_fully(sd_bus_track *track, const char *name) { | |||
| 98 | struct track_item *i; | |||
| 99 | ||||
| 100 | assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 100, __PRETTY_FUNCTION__); } while (0); | |||
| 101 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/libsystemd/sd-bus/bus-track.c" , 101, __PRETTY_FUNCTION__); } while (0); | |||
| 102 | ||||
| 103 | i = hashmap_remove(track->names, name); | |||
| 104 | if (!i) | |||
| 105 | return 0; | |||
| 106 | ||||
| 107 | track_item_free(i); | |||
| 108 | ||||
| 109 | bus_track_add_to_queue(track); | |||
| 110 | ||||
| 111 | track->modified = true1; | |||
| 112 | return 1; | |||
| 113 | } | |||
| 114 | ||||
| 115 | _public___attribute__ ((visibility("default"))) int sd_bus_track_new( | |||
| 116 | sd_bus *bus, | |||
| 117 | sd_bus_track **track, | |||
| 118 | sd_bus_track_handler_t handler, | |||
| 119 | void *userdata) { | |||
| 120 | ||||
| 121 | sd_bus_track *t; | |||
| 122 | ||||
| 123 | assert_return(bus, -EINVAL)do { if (!(((__builtin_expect(!!(bus),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/libsystemd/sd-bus/bus-track.c" , 123, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 124 | assert_return(bus = bus_resolve(bus), -ENOPKG)do { if (!(((__builtin_expect(!!(bus = bus_resolve(bus)),1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD, ( "bus = bus_resolve(bus)"), "../src/libsystemd/sd-bus/bus-track.c" , 124, __PRETTY_FUNCTION__), 0))) return (-65); } while (0); | |||
| 125 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 125, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 126 | ||||
| 127 | if (!bus->bus_client) | |||
| 128 | return -EINVAL22; | |||
| 129 | ||||
| 130 | t = new0(sd_bus_track, 1)((sd_bus_track*) calloc((1), sizeof(sd_bus_track))); | |||
| 131 | if (!t) | |||
| 132 | return -ENOMEM12; | |||
| 133 | ||||
| 134 | t->n_ref = 1; | |||
| 135 | t->handler = handler; | |||
| 136 | t->userdata = userdata; | |||
| 137 | t->bus = sd_bus_ref(bus); | |||
| 138 | ||||
| 139 | LIST_PREPEND(tracks, bus->tracks, t)do { typeof(*(bus->tracks)) **_head = &(bus->tracks ), *_item = (t); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/libsystemd/sd-bus/bus-track.c" , 139, __PRETTY_FUNCTION__); } while (0); if ((_item->tracks_next = *_head)) _item->tracks_next->tracks_prev = _item; _item ->tracks_prev = ((void*)0); *_head = _item; } while (0); | |||
| 140 | t->in_list = true1; | |||
| 141 | ||||
| 142 | bus_track_add_to_queue(t); | |||
| 143 | ||||
| 144 | *track = t; | |||
| 145 | return 0; | |||
| 146 | } | |||
| 147 | ||||
| 148 | _public___attribute__ ((visibility("default"))) sd_bus_track* sd_bus_track_ref(sd_bus_track *track) { | |||
| 149 | ||||
| 150 | if (!track) | |||
| 151 | return NULL((void*)0); | |||
| 152 | ||||
| 153 | assert(track->n_ref > 0)do { if ((__builtin_expect(!!(!(track->n_ref > 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("track->n_ref > 0" ), "../src/libsystemd/sd-bus/bus-track.c", 153, __PRETTY_FUNCTION__ ); } while (0); | |||
| 154 | ||||
| 155 | track->n_ref++; | |||
| 156 | ||||
| 157 | return track; | |||
| 158 | } | |||
| 159 | ||||
| 160 | _public___attribute__ ((visibility("default"))) sd_bus_track* sd_bus_track_unref(sd_bus_track *track) { | |||
| 161 | if (!track) | |||
| 162 | return NULL((void*)0); | |||
| 163 | ||||
| 164 | assert(track->n_ref > 0)do { if ((__builtin_expect(!!(!(track->n_ref > 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("track->n_ref > 0" ), "../src/libsystemd/sd-bus/bus-track.c", 164, __PRETTY_FUNCTION__ ); } while (0); | |||
| 165 | track->n_ref--; | |||
| 166 | ||||
| 167 | if (track->n_ref > 0) | |||
| 168 | return NULL((void*)0); | |||
| 169 | ||||
| 170 | if (track->in_list) | |||
| 171 | LIST_REMOVE(tracks, track->bus->tracks, track)do { typeof(*(track->bus->tracks)) **_head = &(track ->bus->tracks), *_item = (track); do { if ((__builtin_expect (!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/libsystemd/sd-bus/bus-track.c", 171, __PRETTY_FUNCTION__ ); } while (0); if (_item->tracks_next) _item->tracks_next ->tracks_prev = _item->tracks_prev; if (_item->tracks_prev ) _item->tracks_prev->tracks_next = _item->tracks_next ; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/libsystemd/sd-bus/bus-track.c", 171, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->tracks_next; } _item->tracks_next = _item->tracks_prev = ((void*)0); } while (0); | |||
| 172 | ||||
| 173 | bus_track_remove_from_queue(track); | |||
| 174 | track->names = hashmap_free_with_destructor(track->names, track_item_free)({ ({ void *_item; while ((_item = hashmap_steal_first(track-> names))) track_item_free(_item); }); hashmap_free(track->names ); }); | |||
| 175 | track->bus = sd_bus_unref(track->bus); | |||
| 176 | ||||
| 177 | if (track->destroy_callback) | |||
| 178 | track->destroy_callback(track->userdata); | |||
| 179 | ||||
| 180 | return mfree(track); | |||
| 181 | } | |||
| 182 | ||||
| 183 | static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |||
| 184 | sd_bus_track *track = userdata; | |||
| 185 | const char *name, *old, *new; | |||
| 186 | int r; | |||
| 187 | ||||
| 188 | assert(message)do { if ((__builtin_expect(!!(!(message)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("message"), "../src/libsystemd/sd-bus/bus-track.c" , 188, __PRETTY_FUNCTION__); } while (0); | |||
| 189 | assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 189, __PRETTY_FUNCTION__); } while (0); | |||
| 190 | ||||
| 191 | r = sd_bus_message_read(message, "sss", &name, &old, &new); | |||
| 192 | if (r < 0) | |||
| 193 | return 0; | |||
| 194 | ||||
| 195 | bus_track_remove_name_fully(track, name); | |||
| 196 | return 0; | |||
| 197 | } | |||
| 198 | ||||
| 199 | _public___attribute__ ((visibility("default"))) int sd_bus_track_add_name(sd_bus_track *track, const char *name) { | |||
| 200 | _cleanup_(track_item_freep)__attribute__((cleanup(track_item_freep))) struct track_item *n = NULL((void*)0); | |||
| 201 | struct track_item *i; | |||
| 202 | const char *match; | |||
| 203 | int r; | |||
| 204 | ||||
| 205 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 205, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 206 | assert_return(service_name_is_valid(name), -EINVAL)do { if (!(((__builtin_expect(!!(service_name_is_valid(name)) ,1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("service_name_is_valid(name)"), "../src/libsystemd/sd-bus/bus-track.c" , 206, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 207 | ||||
| 208 | i = hashmap_get(track->names, name); | |||
| 209 | if (i) { | |||
| 210 | if (track->recursive) { | |||
| 211 | unsigned k = track->n_ref + 1; | |||
| 212 | ||||
| 213 | if (k < track->n_ref) /* Check for overflow */ | |||
| 214 | return -EOVERFLOW75; | |||
| 215 | ||||
| 216 | track->n_ref = k; | |||
| 217 | } | |||
| 218 | ||||
| 219 | bus_track_remove_from_queue(track); | |||
| 220 | return 0; | |||
| 221 | } | |||
| 222 | ||||
| 223 | r = hashmap_ensure_allocated(&track->names, &string_hash_ops)internal_hashmap_ensure_allocated(&track->names, & string_hash_ops ); | |||
| 224 | if (r < 0) | |||
| 225 | return r; | |||
| 226 | ||||
| 227 | n = new0(struct track_item, 1)((struct track_item*) calloc((1), sizeof(struct track_item))); | |||
| 228 | if (!n) | |||
| 229 | return -ENOMEM12; | |||
| 230 | n->name = strdup(name); | |||
| 231 | if (!n->name) | |||
| 232 | return -ENOMEM12; | |||
| ||||
| 233 | ||||
| 234 | /* First, subscribe to this name */ | |||
| 235 | match = MATCH_FOR_NAME(name)({ const char *_appendees_[] = { "type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," "arg0='", name, "'" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
| 236 | ||||
| 237 | bus_track_remove_from_queue(track); /* don't dispatch this while we work in it */ | |||
| 238 | ||||
| 239 | r = sd_bus_add_match_async(track->bus, &n->slot, match, on_name_owner_changed, NULL((void*)0), track); | |||
| 240 | if (r < 0) { | |||
| 241 | bus_track_add_to_queue(track); | |||
| 242 | return r; | |||
| 243 | } | |||
| 244 | ||||
| 245 | r = hashmap_put(track->names, n->name, n); | |||
| 246 | if (r < 0) { | |||
| 247 | bus_track_add_to_queue(track); | |||
| 248 | return r; | |||
| 249 | } | |||
| 250 | ||||
| 251 | /* Second, check if it is currently existing, or maybe doesn't, or maybe disappeared already. */ | |||
| 252 | track->n_adding++; /* again, make sure this isn't dispatch while we are working in it */ | |||
| 253 | r = sd_bus_get_name_creds(track->bus, name, 0, NULL((void*)0)); | |||
| 254 | track->n_adding--; | |||
| 255 | if (r < 0) { | |||
| 256 | hashmap_remove(track->names, name); | |||
| 257 | bus_track_add_to_queue(track); | |||
| 258 | return r; | |||
| 259 | } | |||
| 260 | ||||
| 261 | n->n_ref = 1; | |||
| 262 | n = NULL((void*)0); | |||
| 263 | ||||
| 264 | bus_track_remove_from_queue(track); | |||
| 265 | track->modified = true1; | |||
| 266 | ||||
| 267 | return 1; | |||
| 268 | } | |||
| 269 | ||||
| 270 | _public___attribute__ ((visibility("default"))) int sd_bus_track_remove_name(sd_bus_track *track, const char *name) { | |||
| 271 | struct track_item *i; | |||
| 272 | ||||
| 273 | assert_return(name, -EINVAL)do { if (!(((__builtin_expect(!!(name),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("name"), "../src/libsystemd/sd-bus/bus-track.c" , 273, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 274 | ||||
| 275 | if (!track) /* Treat a NULL track object as an empty track object */ | |||
| 276 | return 0; | |||
| 277 | ||||
| 278 | if (!track->recursive) | |||
| 279 | return bus_track_remove_name_fully(track, name); | |||
| 280 | ||||
| 281 | i = hashmap_get(track->names, name); | |||
| 282 | if (!i) | |||
| 283 | return -EUNATCH49; | |||
| 284 | if (i->n_ref <= 0) | |||
| 285 | return -EUNATCH49; | |||
| 286 | ||||
| 287 | i->n_ref--; | |||
| 288 | ||||
| 289 | if (i->n_ref <= 0) | |||
| 290 | return bus_track_remove_name_fully(track, name); | |||
| 291 | ||||
| 292 | return 1; | |||
| 293 | } | |||
| 294 | ||||
| 295 | _public___attribute__ ((visibility("default"))) unsigned sd_bus_track_count(sd_bus_track *track) { | |||
| 296 | ||||
| 297 | if (!track) /* Let's consider a NULL object equivalent to an empty object */ | |||
| 298 | return 0; | |||
| 299 | ||||
| 300 | /* This signature really should have returned an int, so that we can propagate errors. But well, ... Also, note | |||
| 301 | * that this returns the number of names being watched, and multiple references to the same name are not | |||
| 302 | * counted. */ | |||
| 303 | ||||
| 304 | return hashmap_size(track->names); | |||
| 305 | } | |||
| 306 | ||||
| 307 | _public___attribute__ ((visibility("default"))) const char* sd_bus_track_contains(sd_bus_track *track, const char *name) { | |||
| 308 | assert_return(name, NULL)do { if (!(((__builtin_expect(!!(name),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("name"), "../src/libsystemd/sd-bus/bus-track.c" , 308, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
| 309 | ||||
| 310 | if (!track) /* Let's consider a NULL object equivalent to an empty object */ | |||
| 311 | return NULL((void*)0); | |||
| 312 | ||||
| 313 | return hashmap_get(track->names, (void*) name) ? name : NULL((void*)0); | |||
| 314 | } | |||
| 315 | ||||
| 316 | _public___attribute__ ((visibility("default"))) const char* sd_bus_track_first(sd_bus_track *track) { | |||
| 317 | const char *n = NULL((void*)0); | |||
| 318 | ||||
| 319 | if (!track) | |||
| 320 | return NULL((void*)0); | |||
| 321 | ||||
| 322 | track->modified = false0; | |||
| 323 | track->iterator = ITERATOR_FIRST((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .next_key = ( (void*)0) }); | |||
| 324 | ||||
| 325 | hashmap_iterate(track->names, &track->iterator, NULL((void*)0), (const void**) &n); | |||
| 326 | return n; | |||
| 327 | } | |||
| 328 | ||||
| 329 | _public___attribute__ ((visibility("default"))) const char* sd_bus_track_next(sd_bus_track *track) { | |||
| 330 | const char *n = NULL((void*)0); | |||
| 331 | ||||
| 332 | if (!track) | |||
| 333 | return NULL((void*)0); | |||
| 334 | ||||
| 335 | if (track->modified) | |||
| 336 | return NULL((void*)0); | |||
| 337 | ||||
| 338 | hashmap_iterate(track->names, &track->iterator, NULL((void*)0), (const void**) &n); | |||
| 339 | return n; | |||
| 340 | } | |||
| 341 | ||||
| 342 | _public___attribute__ ((visibility("default"))) int sd_bus_track_add_sender(sd_bus_track *track, sd_bus_message *m) { | |||
| 343 | const char *sender; | |||
| 344 | ||||
| 345 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 345, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| ||||
| 346 | assert_return(m, -EINVAL)do { if (!(((__builtin_expect(!!(m),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-track.c" , 346, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 347 | ||||
| 348 | if (sd_bus_message_get_bus(m) != track->bus) | |||
| 349 | return -EINVAL22; | |||
| 350 | ||||
| 351 | sender = sd_bus_message_get_sender(m); | |||
| 352 | if (!sender) | |||
| 353 | return -EINVAL22; | |||
| 354 | ||||
| 355 | return sd_bus_track_add_name(track, sender); | |||
| 356 | } | |||
| 357 | ||||
| 358 | _public___attribute__ ((visibility("default"))) int sd_bus_track_remove_sender(sd_bus_track *track, sd_bus_message *m) { | |||
| 359 | const char *sender; | |||
| 360 | ||||
| 361 | assert_return(m, -EINVAL)do { if (!(((__builtin_expect(!!(m),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-track.c" , 361, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 362 | ||||
| 363 | if (!track) /* Treat a NULL track object as an empty track object */ | |||
| 364 | return 0; | |||
| 365 | ||||
| 366 | if (sd_bus_message_get_bus(m) != track->bus) | |||
| 367 | return -EINVAL22; | |||
| 368 | ||||
| 369 | sender = sd_bus_message_get_sender(m); | |||
| 370 | if (!sender) | |||
| 371 | return -EINVAL22; | |||
| 372 | ||||
| 373 | return sd_bus_track_remove_name(track, sender); | |||
| 374 | } | |||
| 375 | ||||
| 376 | _public___attribute__ ((visibility("default"))) sd_bus* sd_bus_track_get_bus(sd_bus_track *track) { | |||
| 377 | assert_return(track, NULL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 377, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
| 378 | ||||
| 379 | return track->bus; | |||
| 380 | } | |||
| 381 | ||||
| 382 | void bus_track_dispatch(sd_bus_track *track) { | |||
| 383 | int r; | |||
| 384 | ||||
| 385 | assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 385, __PRETTY_FUNCTION__); } while (0); | |||
| 386 | assert(track->handler)do { if ((__builtin_expect(!!(!(track->handler)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track->handler"), "../src/libsystemd/sd-bus/bus-track.c" , 386, __PRETTY_FUNCTION__); } while (0); | |||
| 387 | ||||
| 388 | bus_track_remove_from_queue(track); | |||
| 389 | ||||
| 390 | sd_bus_track_ref(track); | |||
| 391 | ||||
| 392 | r = track->handler(track, track->userdata); | |||
| 393 | if (r < 0) | |||
| 394 | log_debug_errno(r, "Failed to process track handler: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/libsystemd/sd-bus/bus-track.c", 394, __func__, "Failed to process track handler: %m" ) : -abs(_e); }); | |||
| 395 | else if (r == 0) | |||
| 396 | bus_track_add_to_queue(track); | |||
| 397 | ||||
| 398 | sd_bus_track_unref(track); | |||
| 399 | } | |||
| 400 | ||||
| 401 | void bus_track_close(sd_bus_track *track) { | |||
| 402 | assert(track)do { if ((__builtin_expect(!!(!(track)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 402, __PRETTY_FUNCTION__); } while (0); | |||
| 403 | ||||
| 404 | /* Called whenever our bus connected is closed. If so, and our track object is non-empty, dispatch it | |||
| 405 | * immediately, as we are closing now, but first flush out all names. */ | |||
| 406 | ||||
| 407 | if (!track->in_list) | |||
| 408 | return; /* We already closed this one, don't close it again. */ | |||
| 409 | ||||
| 410 | /* Remember that this one is closed now */ | |||
| 411 | LIST_REMOVE(tracks, track->bus->tracks, track)do { typeof(*(track->bus->tracks)) **_head = &(track ->bus->tracks), *_item = (track); do { if ((__builtin_expect (!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/libsystemd/sd-bus/bus-track.c", 411, __PRETTY_FUNCTION__ ); } while (0); if (_item->tracks_next) _item->tracks_next ->tracks_prev = _item->tracks_prev; if (_item->tracks_prev ) _item->tracks_prev->tracks_next = _item->tracks_next ; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/libsystemd/sd-bus/bus-track.c", 411, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->tracks_next; } _item->tracks_next = _item->tracks_prev = ((void*)0); } while (0); | |||
| 412 | track->in_list = false0; | |||
| 413 | ||||
| 414 | /* If there's no name in this one anyway, we don't have to dispatch */ | |||
| 415 | if (hashmap_isempty(track->names)) | |||
| 416 | return; | |||
| 417 | ||||
| 418 | /* Let's flush out all names */ | |||
| 419 | hashmap_clear_with_destructor(track->names, track_item_free)({ void *_item; while ((_item = hashmap_steal_first(track-> names))) track_item_free(_item); }); | |||
| 420 | ||||
| 421 | /* Invoke handler */ | |||
| 422 | if (track->handler) | |||
| 423 | bus_track_dispatch(track); | |||
| 424 | } | |||
| 425 | ||||
| 426 | _public___attribute__ ((visibility("default"))) void *sd_bus_track_get_userdata(sd_bus_track *track) { | |||
| 427 | assert_return(track, NULL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 427, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
| 428 | ||||
| 429 | return track->userdata; | |||
| 430 | } | |||
| 431 | ||||
| 432 | _public___attribute__ ((visibility("default"))) void *sd_bus_track_set_userdata(sd_bus_track *track, void *userdata) { | |||
| 433 | void *ret; | |||
| 434 | ||||
| 435 | assert_return(track, NULL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 435, __PRETTY_FUNCTION__), 0))) return (((void*)0)); } while (0); | |||
| 436 | ||||
| 437 | ret = track->userdata; | |||
| 438 | track->userdata = userdata; | |||
| 439 | ||||
| 440 | return ret; | |||
| 441 | } | |||
| 442 | ||||
| 443 | _public___attribute__ ((visibility("default"))) int sd_bus_track_set_destroy_callback(sd_bus_track *track, sd_bus_destroy_t callback) { | |||
| 444 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 444, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 445 | ||||
| 446 | track->destroy_callback = callback; | |||
| 447 | return 0; | |||
| 448 | } | |||
| 449 | ||||
| 450 | _public___attribute__ ((visibility("default"))) int sd_bus_track_get_destroy_callback(sd_bus_track *track, sd_bus_destroy_t *ret) { | |||
| 451 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 451, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 452 | ||||
| 453 | if (ret) | |||
| 454 | *ret = track->destroy_callback; | |||
| 455 | ||||
| 456 | return !!track->destroy_callback; | |||
| 457 | } | |||
| 458 | ||||
| 459 | _public___attribute__ ((visibility("default"))) int sd_bus_track_set_recursive(sd_bus_track *track, int b) { | |||
| 460 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 460, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 461 | ||||
| 462 | if (track->recursive == !!b) | |||
| 463 | return 0; | |||
| 464 | ||||
| 465 | if (!hashmap_isempty(track->names)) | |||
| 466 | return -EBUSY16; | |||
| 467 | ||||
| 468 | track->recursive = b; | |||
| 469 | return 0; | |||
| 470 | } | |||
| 471 | ||||
| 472 | _public___attribute__ ((visibility("default"))) int sd_bus_track_get_recursive(sd_bus_track *track) { | |||
| 473 | assert_return(track, -EINVAL)do { if (!(((__builtin_expect(!!(track),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("track"), "../src/libsystemd/sd-bus/bus-track.c" , 473, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 474 | ||||
| 475 | return track->recursive; | |||
| 476 | } | |||
| 477 | ||||
| 478 | _public___attribute__ ((visibility("default"))) int sd_bus_track_count_sender(sd_bus_track *track, sd_bus_message *m) { | |||
| 479 | const char *sender; | |||
| 480 | ||||
| 481 | assert_return(m, -EINVAL)do { if (!(((__builtin_expect(!!(m),1))) ? (1) : (log_assert_failed_return_realm (LOG_REALM_SYSTEMD, ("m"), "../src/libsystemd/sd-bus/bus-track.c" , 481, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 482 | ||||
| 483 | if (!track) /* Let's consider a NULL object equivalent to an empty object */ | |||
| 484 | return 0; | |||
| 485 | ||||
| 486 | if (sd_bus_message_get_bus(m) != track->bus) | |||
| 487 | return -EINVAL22; | |||
| 488 | ||||
| 489 | sender = sd_bus_message_get_sender(m); | |||
| 490 | if (!sender) | |||
| 491 | return -EINVAL22; | |||
| 492 | ||||
| 493 | return sd_bus_track_count_name(track, sender); | |||
| 494 | } | |||
| 495 | ||||
| 496 | _public___attribute__ ((visibility("default"))) int sd_bus_track_count_name(sd_bus_track *track, const char *name) { | |||
| 497 | struct track_item *i; | |||
| 498 | ||||
| 499 | assert_return(service_name_is_valid(name), -EINVAL)do { if (!(((__builtin_expect(!!(service_name_is_valid(name)) ,1))) ? (1) : (log_assert_failed_return_realm(LOG_REALM_SYSTEMD , ("service_name_is_valid(name)"), "../src/libsystemd/sd-bus/bus-track.c" , 499, __PRETTY_FUNCTION__), 0))) return (-22); } while (0); | |||
| 500 | ||||
| 501 | if (!track) /* Let's consider a NULL object equivalent to an empty object */ | |||
| 502 | return 0; | |||
| 503 | ||||
| 504 | i = hashmap_get(track->names, name); | |||
| 505 | if (!i) | |||
| 506 | return 0; | |||
| 507 | ||||
| 508 | return i->n_ref; | |||
| 509 | } |