2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
23 #include "bus-internal.h"
24 #include "bus-track.h"
30 sd_bus_track_handler_t handler
;
33 LIST_FIELDS(sd_bus_track
, queue
);
39 #define MATCH_PREFIX \
41 "sender='org.freedesktop.DBus'," \
42 "path='/org/freedesktop/DBus'," \
43 "interface='org.freedesktop.DBus'," \
44 "member='NameOwnerChanged'," \
47 #define MATCH_SUFFIX \
50 #define MATCH_FOR_NAME(name) \
53 size_t _l = strlen(name); \
54 _x = alloca(strlen(MATCH_PREFIX)+_l+strlen(MATCH_SUFFIX)+1); \
55 strcpy(stpcpy(stpcpy(_x, MATCH_PREFIX), name), MATCH_SUFFIX); \
59 static void bus_track_add_to_queue(sd_bus_track
*track
) {
68 LIST_PREPEND(queue
, track
->bus
->track_queue
, track
);
69 track
->in_queue
= true;
72 static void bus_track_remove_from_queue(sd_bus_track
*track
) {
78 LIST_REMOVE(queue
, track
->bus
->track_queue
, track
);
79 track
->in_queue
= false;
82 _public_
int sd_bus_track_new(
85 sd_bus_track_handler_t handler
,
90 assert_return(bus
, -EINVAL
);
91 assert_return(track
, -EINVAL
);
96 t
= new0(sd_bus_track
, 1);
101 t
->handler
= handler
;
102 t
->userdata
= userdata
;
103 t
->bus
= sd_bus_ref(bus
);
105 bus_track_add_to_queue(t
);
111 _public_ sd_bus_track
* sd_bus_track_ref(sd_bus_track
*track
) {
116 assert(track
->n_ref
> 0);
123 _public_ sd_bus_track
* sd_bus_track_unref(sd_bus_track
*track
) {
129 assert(track
->n_ref
> 0);
131 if (track
->n_ref
> 1) {
136 while ((n
= hashmap_first_key(track
->names
)))
137 sd_bus_track_remove_name(track
, n
);
139 bus_track_remove_from_queue(track
);
140 hashmap_free(track
->names
);
141 sd_bus_unref(track
->bus
);
147 static int on_name_owner_changed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
148 sd_bus_track
*track
= userdata
;
149 const char *name
, *old
, *new;
155 r
= sd_bus_message_read(message
, "sss", &name
, &old
, &new);
159 sd_bus_track_remove_name(track
, name
);
163 _public_
int sd_bus_track_add_name(sd_bus_track
*track
, const char *name
) {
164 _cleanup_(sd_bus_slot_unrefp
) sd_bus_slot
*slot
= NULL
;
165 _cleanup_free_
char *n
= NULL
;
169 assert_return(track
, -EINVAL
);
170 assert_return(service_name_is_valid(name
), -EINVAL
);
172 r
= hashmap_ensure_allocated(&track
->names
, &string_hash_ops
);
180 /* First, subscribe to this name */
181 match
= MATCH_FOR_NAME(n
);
182 r
= sd_bus_add_match(track
->bus
, &slot
, match
, on_name_owner_changed
, track
);
186 r
= hashmap_put(track
->names
, n
, slot
);
192 /* Second, check if it is currently existing, or maybe
193 * doesn't, or maybe disappeared already. */
194 r
= sd_bus_get_name_creds(track
->bus
, n
, 0, NULL
);
196 hashmap_remove(track
->names
, n
);
203 bus_track_remove_from_queue(track
);
204 track
->modified
= true;
209 _public_
int sd_bus_track_remove_name(sd_bus_track
*track
, const char *name
) {
210 _cleanup_(sd_bus_slot_unrefp
) sd_bus_slot
*slot
= NULL
;
211 _cleanup_free_
char *n
= NULL
;
213 assert_return(name
, -EINVAL
);
218 slot
= hashmap_remove2(track
->names
, (char*) name
, (void**) &n
);
222 if (hashmap_isempty(track
->names
))
223 bus_track_add_to_queue(track
);
225 track
->modified
= true;
230 _public_
unsigned sd_bus_track_count(sd_bus_track
*track
) {
234 return hashmap_size(track
->names
);
237 _public_
const char* sd_bus_track_contains(sd_bus_track
*track
, const char *name
) {
238 assert_return(track
, NULL
);
239 assert_return(name
, NULL
);
241 return hashmap_get(track
->names
, (void*) name
) ? name
: NULL
;
244 _public_
const char* sd_bus_track_first(sd_bus_track
*track
) {
245 const char *n
= NULL
;
250 track
->modified
= false;
251 track
->iterator
= ITERATOR_FIRST
;
253 hashmap_iterate(track
->names
, &track
->iterator
, NULL
, (const void**) &n
);
257 _public_
const char* sd_bus_track_next(sd_bus_track
*track
) {
258 const char *n
= NULL
;
266 hashmap_iterate(track
->names
, &track
->iterator
, NULL
, (const void**) &n
);
270 _public_
int sd_bus_track_add_sender(sd_bus_track
*track
, sd_bus_message
*m
) {
273 assert_return(track
, -EINVAL
);
274 assert_return(m
, -EINVAL
);
276 sender
= sd_bus_message_get_sender(m
);
280 return sd_bus_track_add_name(track
, sender
);
283 _public_
int sd_bus_track_remove_sender(sd_bus_track
*track
, sd_bus_message
*m
) {
286 assert_return(track
, -EINVAL
);
287 assert_return(m
, -EINVAL
);
289 sender
= sd_bus_message_get_sender(m
);
293 return sd_bus_track_remove_name(track
, sender
);
296 _public_ sd_bus
* sd_bus_track_get_bus(sd_bus_track
*track
) {
297 assert_return(track
, NULL
);
302 void bus_track_dispatch(sd_bus_track
*track
) {
306 assert(track
->in_queue
);
307 assert(track
->handler
);
309 bus_track_remove_from_queue(track
);
311 sd_bus_track_ref(track
);
313 r
= track
->handler(track
, track
->userdata
);
315 log_debug_errno(r
, "Failed to process track handler: %m");
317 bus_track_add_to_queue(track
);
319 sd_bus_track_unref(track
);
322 _public_
void *sd_bus_track_get_userdata(sd_bus_track
*track
) {
323 assert_return(track
, NULL
);
325 return track
->userdata
;
328 _public_
void *sd_bus_track_set_userdata(sd_bus_track
*track
, void *userdata
) {
331 assert_return(track
, NULL
);
333 ret
= track
->userdata
;
334 track
->userdata
= userdata
;