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