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/>.
22 #include "dbus-client-track.h"
24 static unsigned tracked_client_hash(const void *a) {
25 const BusTrackedClient *x = a;
27 return string_hash_func(x->name) ^ PTR_TO_UINT(x->bus);
30 static int tracked_client_compare(const void *a, const void *b) {
31 const BusTrackedClient *x = a, *y = b;
34 r = strcmp(x->name, y->name);
46 static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
47 BusTrackedClient *c = userdata;
48 const char *name, *old, *new;
54 r = sd_bus_message_read(message, "sss", &name, &old, &new);
56 log_debug("Failed to parse NameOwnerChanged message.");
60 bus_client_untrack(c->set, bus, name);
64 static char *build_match(const char *name) {
66 return strjoin("type='signal',"
67 "sender='org.freedesktop.DBus',"
68 "path='/org/freedesktop/DBus',"
69 "interface='org.freedesktop.DBus',"
70 "member='NameOwnerChanged',"
71 "arg0='", name, "'", NULL);
74 int bus_client_track(Set **s, sd_bus *bus, const char *name) {
75 BusTrackedClient *c, *found;
82 r = set_ensure_allocated(s, tracked_client_hash, tracked_client_compare);
86 name = strempty(name);
90 c = alloca(offsetof(BusTrackedClient, name) + l + 1);
93 strcpy(c->name, name);
95 found = set_get(*s, c);
99 c = memdup(c, offsetof(BusTrackedClient, name) + l + 1);
109 if (!isempty(name)) {
110 _cleanup_free_ char *match = NULL;
112 match = build_match(name);
119 r = sd_bus_add_match(bus, match, on_name_owner_changed, c);
131 static void bus_client_free_one(Set *s, BusTrackedClient *c) {
135 if (!isempty(c->name)) {
136 _cleanup_free_ char *match = NULL;
138 match = build_match(c->name);
140 sd_bus_remove_match(c->bus, match, on_name_owner_changed, c);
143 sd_bus_unref(c->bus);
148 int bus_client_untrack(Set *s, sd_bus *bus, const char *name) {
149 BusTrackedClient *c, *found;
156 name = strempty(name);
160 c = alloca(offsetof(BusTrackedClient, name) + l + 1);
162 strcpy(c->name, name);
164 found = set_get(s, c);
168 bus_client_free_one(s, found);
172 void bus_client_track_free(Set *s) {
175 while ((c = set_first(s)))
176 bus_client_free_one(s, c);
181 int bus_client_untrack_bus(Set *s, sd_bus *bus) {
188 bus_client_free_one(s, c);
195 void bus_client_track_serialize(Manager *m, FILE *f, Set *s) {
202 SET_FOREACH(c, s, i) {
203 if (c->bus == m->api_bus)
204 fprintf(f, "subscribed=%s", isempty(c->name) ? "*" : c->name);
206 fprintf(f, "subscribed=%p %s", c->bus, isempty(c->name) ? "*" : c->name);
210 int bus_client_track_deserialize_item(Manager *m, Set **s, const char *line) {
211 const char *e, *q, *name;
216 e = startswith(line, "subscribed=");
220 q = strpbrk(e, WHITESPACE);
231 if (sscanf(e, "%p", &p) != 1) {
232 log_debug("Failed to parse subscription pointer.");
236 bus = set_get(m->private_buses, p);
240 name = q + strspn(q, WHITESPACE);
243 r = bus_client_track(s, bus, streq(name, "*") ? NULL : name);
245 log_debug("Failed to deserialize client subscription: %s", strerror(-r));