1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
23 #include "dbus-client-track.h"
25 static unsigned long tracked_client_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
26 const BusTrackedClient *x = a;
28 return string_hash_func(x->name, hash_key) ^ trivial_hash_func(x->bus, hash_key);
31 static int tracked_client_compare(const void *a, const void *b) {
32 const BusTrackedClient *x = a, *y = b;
35 r = strcmp(x->name, y->name);
47 static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
48 BusTrackedClient *c = userdata;
49 const char *name, *old, *new;
55 r = sd_bus_message_read(message, "sss", &name, &old, &new);
57 bus_log_parse_error(r);
61 bus_client_untrack(c->set, bus, name);
65 static char *build_match(const char *name) {
67 return strjoin("type='signal',"
68 "sender='org.freedesktop.DBus',"
69 "path='/org/freedesktop/DBus',"
70 "interface='org.freedesktop.DBus',"
71 "member='NameOwnerChanged',"
72 "arg0='", name, "'", NULL);
75 int bus_client_track(Set **s, sd_bus *bus, const char *name) {
76 BusTrackedClient *c, *found;
83 r = set_ensure_allocated(s, tracked_client_hash, tracked_client_compare);
87 name = strempty(name);
91 c = alloca(offsetof(BusTrackedClient, name) + l + 1);
94 strcpy(c->name, name);
96 found = set_get(*s, c);
100 c = memdup(c, offsetof(BusTrackedClient, name) + l + 1);
110 if (!isempty(name)) {
111 _cleanup_free_ char *match = NULL;
113 match = build_match(name);
120 r = sd_bus_add_match(bus, match, on_name_owner_changed, c);
132 static void bus_client_free_one(Set *s, BusTrackedClient *c) {
136 if (!isempty(c->name)) {
137 _cleanup_free_ char *match = NULL;
139 match = build_match(c->name);
141 sd_bus_remove_match(c->bus, match, on_name_owner_changed, c);
144 sd_bus_unref(c->bus);
149 int bus_client_untrack(Set *s, sd_bus *bus, const char *name) {
150 BusTrackedClient *c, *found;
157 name = strempty(name);
161 c = alloca(offsetof(BusTrackedClient, name) + l + 1);
163 strcpy(c->name, name);
165 found = set_get(s, c);
169 bus_client_free_one(s, found);
173 void bus_client_track_free(Set *s) {
176 while ((c = set_first(s)))
177 bus_client_free_one(s, c);
182 int bus_client_untrack_bus(Set *s, sd_bus *bus) {
189 bus_client_free_one(s, c);
196 void bus_client_track_serialize(Manager *m, FILE *f, Set *s) {
203 SET_FOREACH(c, s, i) {
204 if (c->bus == m->api_bus)
205 fprintf(f, "subscribed=%s\n", isempty(c->name) ? "*" : c->name);
207 fprintf(f, "subscribed=%p %s\n", c->bus, isempty(c->name) ? "*" : c->name);
211 int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line) {
212 const char *e, *q, *name;
217 e = startswith(line, "subscribed=");
221 q = strpbrk(e, WHITESPACE);
232 if (sscanf(e, "%p", &p) != 1) {
233 log_debug("Failed to parse subscription pointer.");
237 bus = set_get(m->private_buses, p);
241 name = q + strspn(q, WHITESPACE);
244 r = bus_client_track(s, bus, streq(name, "*") ? NULL : name);
246 log_debug("Failed to deserialize client subscription: %s", strerror(-r));