chiark / gitweb /
timedated: use libsystemd-bus instead of libdbus for bus communication
[elogind.git] / src / libsystemd-bus / bus-control.c
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 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <stddef.h>
27 #include <errno.h>
28
29 #include "strv.h"
30
31 #include "sd-bus.h"
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-control.h"
35 #include "bus-bloom.h"
36 #include "bus-util.h"
37
38 int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
39         int r;
40
41         if (!bus)
42                 return -EINVAL;
43         if (!unique)
44                 return -EINVAL;
45         if (bus_pid_changed(bus))
46                 return -ECHILD;
47
48         r = bus_ensure_running(bus);
49         if (r < 0)
50                 return r;
51
52         *unique = bus->unique_name;
53         return 0;
54 }
55
56 int sd_bus_request_name(sd_bus *bus, const char *name, int flags) {
57         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
58         uint32_t ret;
59         int r;
60
61         if (!bus)
62                 return -EINVAL;
63         if (!name)
64                 return -EINVAL;
65         if (!bus->bus_client)
66                 return -EINVAL;
67         if (!BUS_IS_OPEN(bus->state))
68                 return -ENOTCONN;
69         if (bus_pid_changed(bus))
70                 return -ECHILD;
71
72         if (bus->is_kernel) {
73                 struct kdbus_cmd_name *n;
74                 size_t l;
75
76                 l = strlen(name);
77                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
78                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
79                 n->flags = flags;
80                 memcpy(n->name, name, l+1);
81
82 #ifdef HAVE_VALGRIND_MEMCHECK_H
83                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
84 #endif
85
86                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
87                 if (r < 0)
88                         return -errno;
89
90                 return n->flags;
91         } else {
92                 r = sd_bus_call_method(
93                                 bus,
94                                 "org.freedesktop.DBus",
95                                 "/",
96                                 "org.freedesktop.DBus",
97                                 "RequestName",
98                                 NULL,
99                                 &reply,
100                                 "su",
101                                 name,
102                                 flags);
103                 if (r < 0)
104                         return r;
105
106                 r = sd_bus_message_read(reply, "u", &ret);
107                 if (r < 0)
108                         return r;
109
110                 return ret;
111         }
112 }
113
114 int sd_bus_release_name(sd_bus *bus, const char *name) {
115         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
116         uint32_t ret;
117         int r;
118
119         if (!bus)
120                 return -EINVAL;
121         if (!name)
122                 return -EINVAL;
123         if (!bus->bus_client)
124                 return -EINVAL;
125         if (!BUS_IS_OPEN(bus->state))
126                 return -ENOTCONN;
127         if (bus_pid_changed(bus))
128                 return -ECHILD;
129
130         if (bus->is_kernel) {
131                 struct kdbus_cmd_name *n;
132                 size_t l;
133
134                 l = strlen(name);
135                 n = alloca0(offsetof(struct kdbus_cmd_name, name) + l + 1);
136                 n->size = offsetof(struct kdbus_cmd_name, name) + l + 1;
137                 memcpy(n->name, name, l+1);
138
139 #ifdef HAVE_VALGRIND_MEMCHECK_H
140                 VALGRIND_MAKE_MEM_DEFINED(n, n->size);
141 #endif
142                 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
143                 if (r < 0)
144                         return -errno;
145
146                 return n->flags;
147         } else {
148                 r = sd_bus_call_method(
149                                 bus,
150                                 "org.freedesktop.DBus",
151                                 "/",
152                                 "org.freedesktop.DBus",
153                                 "ReleaseName",
154                                 NULL,
155                                 &reply,
156                                 "s",
157                                 name);
158                 if (r < 0)
159                         return r;
160
161                 r = sd_bus_message_read(reply, "u", &ret);
162                 if (r < 0)
163                         return r;
164         }
165
166         return ret;
167 }
168
169 int sd_bus_list_names(sd_bus *bus, char ***l) {
170         _cleanup_bus_message_unref_ sd_bus_message *reply1 = NULL, *reply2 = NULL;
171         char **x = NULL;
172         int r;
173
174         if (!bus)
175                 return -EINVAL;
176         if (!l)
177                 return -EINVAL;
178         if (!BUS_IS_OPEN(bus->state))
179                 return -ENOTCONN;
180         if (bus_pid_changed(bus))
181                 return -ECHILD;
182
183         r = sd_bus_call_method(
184                         bus,
185                         "org.freedesktop.DBus",
186                         "/",
187                         "org.freedesktop.DBus",
188                         "ListNames",
189                         NULL,
190                         &reply1,
191                         NULL);
192         if (r < 0)
193                 return r;
194
195         r = sd_bus_call_method(
196                         bus,
197                         "org.freedesktop.DBus",
198                         "/",
199                         "org.freedesktop.DBus",
200                         "ListActivatableNames",
201                         NULL,
202                         &reply2,
203                         NULL);
204         if (r < 0)
205                 return r;
206
207         r = bus_message_read_strv_extend(reply1, &x);
208         if (r < 0) {
209                 strv_free(x);
210                 return r;
211         }
212
213         r = bus_message_read_strv_extend(reply2, &x);
214         if (r < 0) {
215                 strv_free(x);
216                 return r;
217         }
218
219         *l = strv_uniq(x);
220         return 0;
221 }
222
223 int sd_bus_get_owner(sd_bus *bus, const char *name, char **owner) {
224         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
225         const char *found;
226         int r;
227
228         if (!bus)
229                 return -EINVAL;
230         if (!name)
231                 return -EINVAL;
232         if (!BUS_IS_OPEN(bus->state))
233                 return -ENOTCONN;
234         if (bus_pid_changed(bus))
235                 return -ECHILD;
236
237         r = sd_bus_call_method(
238                         bus,
239                         "org.freedesktop.DBus",
240                         "/",
241                         "org.freedesktop.DBus",
242                         "GetNameOwner",
243                         NULL,
244                         &reply,
245                         "s",
246                         name);
247         if (r < 0)
248                 return r;
249
250         r = sd_bus_message_read(reply, "s", &found);
251         if (r < 0)
252                 return r;
253
254         if (owner) {
255                 char *t;
256
257                 t = strdup(found);
258                 if (!t)
259                         return -ENOMEM;
260
261                 *owner = t;
262         }
263
264         return 0;
265 }
266
267 int sd_bus_get_owner_uid(sd_bus *bus, const char *name, uid_t *uid) {
268         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
269         uint32_t u;
270         int r;
271
272         if (!bus)
273                 return -EINVAL;
274         if (!name)
275                 return -EINVAL;
276         if (!uid)
277                 return -EINVAL;
278         if (!BUS_IS_OPEN(bus->state))
279                 return -ENOTCONN;
280         if (bus_pid_changed(bus))
281                 return -ECHILD;
282
283         r = sd_bus_call_method(
284                         bus,
285                         "org.freedesktop.DBus",
286                         "/",
287                         "org.freedesktop.DBus",
288                         "GetConnectionUnixUser",
289                         NULL,
290                         &reply,
291                         "s",
292                         name);
293         if (r < 0)
294                 return r;
295
296         r = sd_bus_message_read(reply, "u", &u);
297         if (r < 0)
298                 return r;
299
300         *uid = (uid_t) u;
301         return 0;
302 }
303
304 int sd_bus_get_owner_pid(sd_bus *bus, const char *name, pid_t *pid) {
305         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
306         uint32_t u;
307         int r;
308
309         if (!bus)
310                 return -EINVAL;
311         if (!name)
312                 return -EINVAL;
313         if (!pid)
314                 return -EINVAL;
315         if (!BUS_IS_OPEN(bus->state))
316                 return -ENOTCONN;
317         if (bus_pid_changed(bus))
318                 return -ECHILD;
319
320         r = sd_bus_call_method(
321                         bus,
322                         "org.freedesktop.DBus",
323                         "/",
324                         "org.freedesktop.DBus",
325                         "GetConnectionUnixProcessID",
326                         NULL,
327                         &reply,
328                         "s",
329                         name);
330         if (r < 0)
331                 return r;
332
333         r = sd_bus_message_read(reply, "u", &u);
334         if (r < 0)
335                 return r;
336
337         if (u == 0)
338                 return -EIO;
339
340         *pid = (uid_t) u;
341         return 0;
342 }
343
344 int bus_add_match_internal(
345                 sd_bus *bus,
346                 const char *match,
347                 struct bus_match_component *components,
348                 unsigned n_components,
349                 uint64_t cookie) {
350
351         int r;
352
353         assert(bus);
354         assert(match);
355
356         if (bus->is_kernel) {
357                 struct kdbus_cmd_match *m;
358                 struct kdbus_item *item;
359                 uint64_t bloom[BLOOM_SIZE/8];
360                 size_t sz;
361                 const char *sender = NULL;
362                 size_t sender_length = 0;
363                 uint64_t src_id = KDBUS_MATCH_SRC_ID_ANY;
364                 bool using_bloom = false;
365                 unsigned i;
366
367                 zero(bloom);
368
369                 sz = offsetof(struct kdbus_cmd_match, items);
370
371                 for (i = 0; i < n_components; i++) {
372                         struct bus_match_component *c = &components[i];
373
374                         switch (c->type) {
375
376                         case BUS_MATCH_SENDER:
377                                 r = bus_kernel_parse_unique_name(c->value_str, &src_id);
378                                 if (r < 0)
379                                         return r;
380
381                                 if (r > 0) {
382                                         sender = c->value_str;
383                                         sender_length = strlen(sender);
384                                         sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
385                                 }
386
387                                 break;
388
389                         case BUS_MATCH_MESSAGE_TYPE:
390                                 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(c->value_u8));
391                                 using_bloom = true;
392                                 break;
393
394                         case BUS_MATCH_INTERFACE:
395                                 bloom_add_pair(bloom, "interface", c->value_str);
396                                 using_bloom = true;
397                                 break;
398
399                         case BUS_MATCH_MEMBER:
400                                 bloom_add_pair(bloom, "member", c->value_str);
401                                 using_bloom = true;
402                                 break;
403
404                         case BUS_MATCH_PATH:
405                                 bloom_add_pair(bloom, "path", c->value_str);
406                                 using_bloom = true;
407                                 break;
408
409                         case BUS_MATCH_PATH_NAMESPACE:
410                                 if (!streq(c->value_str, "/")) {
411                                         bloom_add_pair(bloom, "path-slash-prefix", c->value_str);
412                                         using_bloom = true;
413                                 }
414                                 break;
415
416                         case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
417                                 char buf[sizeof("arg")-1 + 2 + 1];
418
419                                 snprintf(buf, sizeof(buf), "arg%u", c->type - BUS_MATCH_ARG);
420                                 bloom_add_pair(bloom, buf, c->value_str);
421                                 using_bloom = true;
422                                 break;
423                         }
424
425                         case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST: {
426                                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
427
428                                 snprintf(buf, sizeof(buf), "arg%u-slash-prefix", c->type - BUS_MATCH_ARG_PATH);
429                                 bloom_add_pair(bloom, buf, c->value_str);
430                                 using_bloom = true;
431                                 break;
432                         }
433
434                         case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
435                                 char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
436
437                                 snprintf(buf, sizeof(buf), "arg%u-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
438                                 bloom_add_pair(bloom, buf, c->value_str);
439                                 using_bloom = true;
440                                 break;
441                         }
442
443                         case BUS_MATCH_DESTINATION:
444                                 /* The bloom filter does not include
445                                    the destination, since it is only
446                                    available for broadcast messages
447                                    which do not carry a destination
448                                    since they are undirected. */
449                                 break;
450
451                         case BUS_MATCH_ROOT:
452                         case BUS_MATCH_VALUE:
453                         case BUS_MATCH_LEAF:
454                         case _BUS_MATCH_NODE_TYPE_MAX:
455                         case _BUS_MATCH_NODE_TYPE_INVALID:
456                                 assert_not_reached("Invalid match type?");
457                         }
458                 }
459
460                 if (using_bloom)
461                         sz += ALIGN8(offsetof(struct kdbus_item, data64) + BLOOM_SIZE);
462
463                 m = alloca0(sz);
464                 m->size = sz;
465                 m->cookie = cookie;
466                 m->src_id = src_id;
467
468                 item = m->items;
469
470                 if (using_bloom) {
471                         item->size = offsetof(struct kdbus_item, data64) + BLOOM_SIZE;
472                         item->type = KDBUS_MATCH_BLOOM;
473                         memcpy(item->data64, bloom, BLOOM_SIZE);
474
475                         item = KDBUS_ITEM_NEXT(item);
476                 }
477
478                 if (sender) {
479                         item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
480                         item->type = KDBUS_MATCH_SRC_NAME;
481                         memcpy(item->str, sender, sender_length + 1);
482                 }
483
484                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
485                 if (r < 0)
486                         return -errno;
487
488         } else {
489                 return sd_bus_call_method(
490                                 bus,
491                                 "org.freedesktop.DBus",
492                                 "/",
493                                 "org.freedesktop.DBus",
494                                 "AddMatch",
495                                 NULL,
496                                 NULL,
497                                 "s",
498                                 match);
499         }
500
501         return 0;
502 }
503
504 int bus_remove_match_internal(
505                 sd_bus *bus,
506                 const char *match,
507                 uint64_t cookie) {
508
509         int r;
510
511         assert(bus);
512         assert(match);
513
514         if (bus->is_kernel) {
515                 struct kdbus_cmd_match m;
516
517                 zero(m);
518                 m.size = offsetof(struct kdbus_cmd_match, items);
519                 m.cookie = cookie;
520
521                 r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
522                 if (r < 0)
523                         return -errno;
524
525         } else {
526                 return sd_bus_call_method(
527                                 bus,
528                                 "org.freedesktop.DBus",
529                                 "/",
530                                 "org.freedesktop.DBus",
531                                 "RemoveMatch",
532                                 NULL,
533                                 NULL,
534                                 "s",
535                                 match);
536         }
537
538         return 0;
539 }
540
541 int sd_bus_get_owner_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
542         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
543         const char *mid;
544         int r;
545
546         if (!bus)
547                 return -EINVAL;
548         if (!name)
549                 return -EINVAL;
550         if (!BUS_IS_OPEN(bus->state))
551                 return -ENOTCONN;
552         if (bus_pid_changed(bus))
553                 return -ECHILD;
554
555         if (streq_ptr(name, bus->unique_name))
556                 return sd_id128_get_machine(machine);
557
558         r = sd_bus_call_method(bus,
559                                name,
560                                "/",
561                                "org.freedesktop.DBus.Peer",
562                                "GetMachineId",
563                                NULL,
564                                &reply,
565                                NULL);
566
567         if (r < 0)
568                 return r;
569
570         r = sd_bus_message_read(reply, "s", &mid);
571         if (r < 0)
572                 return r;
573
574         return sd_id128_from_string(mid, machine);
575 }