]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-driverd/bus-driverd.c
8888a07082996bc80abda7b27b0d0609f18f7c18
[thirdparty/systemd.git] / src / bus-driverd / bus-driverd.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Daniel Mack
5
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.
10
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.
15
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/>.
18 ***/
19
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <locale.h>
25 #include <string.h>
26 #include <poll.h>
27 #include <netdb.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/timex.h>
31 #include <sys/utsname.h>
32 #include <unistd.h>
33
34 #include "kdbus.h"
35 #include "sd-bus.h"
36 #include "bus-internal.h"
37 #include "sd-daemon.h"
38 #include "sd-event.h"
39 #include "event-util.h"
40 #include "bus-util.h"
41 #include "bus-error.h"
42 #include "bus-message.h"
43 #include "bus-kernel.h"
44 #include "socket-util.h"
45 #include "util.h"
46 #include "build.h"
47 #include "strv.h"
48 #include "sd-id128.h"
49 #include "async.h"
50 #include "hashmap.h"
51 #include "def.h"
52 #include "unit-name.h"
53 #include "bus-control.h"
54
55 #define CLIENTS_MAX 1024
56 #define MATCHES_MAX 1024
57
58 typedef struct Match Match;
59 typedef struct Client Client;
60 typedef struct Context Context;
61
62 struct Match {
63 Client *client;
64 char *match;
65 uint64_t cookie;
66 LIST_FIELDS(Match, matches);
67 };
68
69 struct Client {
70 Context *context;
71 uint64_t id;
72 uint64_t next_cookie;
73 Hashmap *matches;
74 unsigned n_matches;
75 char *watch;
76 };
77
78 struct Context {
79 sd_bus *bus;
80 sd_event *event;
81 Hashmap *clients;
82 };
83
84 static void match_free(Match *m) {
85
86 if (!m)
87 return;
88
89 if (m->client) {
90 Match *first;
91
92 first = hashmap_get(m->client->matches, m->match);
93 LIST_REMOVE(matches, first, m);
94 if (first)
95 assert_se(hashmap_replace(m->client->matches, m->match, first) >= 0);
96 else
97 hashmap_remove(m->client->matches, m->match);
98
99 m->client->n_matches--;
100 }
101
102 free(m->match);
103 free(m);
104 }
105
106 static int match_new(Client *c, struct bus_match_component *components, unsigned n_components, Match **_m) {
107 Match *m, *first;
108 int r;
109
110 assert(c);
111 assert(_m);
112
113 r = hashmap_ensure_allocated(&c->matches, string_hash_func, string_compare_func);
114 if (r < 0)
115 return r;
116
117 m = new0(Match, 1);
118 if (!m)
119 return -ENOMEM;
120
121 m->match = bus_match_to_string(components, n_components);
122 if (!m->match) {
123 r = -ENOMEM;
124 goto fail;
125 }
126
127 m->cookie = ++c->next_cookie;
128
129 first = hashmap_get(c->matches, m->match);
130 LIST_PREPEND(matches, first, m);
131 r = hashmap_replace(c->matches, m->match, first);
132 if (r < 0) {
133 LIST_REMOVE(matches, first, m);
134 goto fail;
135 }
136
137 m->client = c;
138 c->n_matches++;
139
140 *_m = m;
141 m = NULL;
142
143 return 0;
144
145 fail:
146 match_free(m);
147 return r;
148 }
149
150 static int on_name_owner_changed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error);
151
152 static void client_free(Client *c) {
153 Match *m;
154
155 if (!c)
156 return;
157
158 if (c->context) {
159 if (c->watch)
160 sd_bus_remove_match(c->context->bus, c->watch, on_name_owner_changed, c);
161
162 assert_se(hashmap_remove(c->context->clients, &c->id) == c);
163 }
164
165 while ((m = hashmap_first(c->matches)))
166 match_free(m);
167
168 hashmap_free(c->matches);
169 free(c->watch);
170
171 free(c);
172 }
173
174 static int on_name_owner_changed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
175 Client *c = userdata;
176
177 assert(bus);
178 assert(m);
179
180 client_free(c);
181 return 0;
182 }
183
184 static int client_acquire(Context *context, uint64_t id, Client **_c) {
185 char *watch = NULL;
186 Client *c;
187 int r;
188
189 assert(context);
190 assert(_c);
191
192 c = hashmap_get(context->clients, &id);
193 if (c) {
194 *_c = c;
195 return 0;
196 }
197
198 if (hashmap_size(context->clients) >= CLIENTS_MAX)
199 return -ENOBUFS;
200
201 r = hashmap_ensure_allocated(&context->clients, uint64_hash_func, uint64_compare_func);
202 if (r < 0)
203 return r;
204
205 c = new0(Client, 1);
206 if (!c)
207 return -ENOMEM;
208
209 c->id = id;
210
211 r = hashmap_put(context->clients, &c->id, c);
212 if (r < 0)
213 goto fail;
214
215 c->context = context;
216
217 if (asprintf(&watch,
218 "type='signal',"
219 "sender='org.freedesktop.DBus',"
220 "path='/org/freedesktop/DBus',"
221 "interface='org.freedesktop.DBus',"
222 "member='NameOwnerChanged',"
223 "arg0=':1.%llu'", (unsigned long long) id) < 0) {
224 r = -ENOMEM;
225 goto fail;
226 }
227
228 r = sd_bus_add_match(context->bus, watch, on_name_owner_changed, c);
229 if (r < 0) {
230 free(watch);
231 goto fail;
232 }
233
234 c->watch = watch;
235
236 *_c = c;
237 return 0;
238
239 fail:
240 client_free(c);
241 return r;
242 }
243
244 static int driver_add_match(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
245
246 struct bus_match_component *components = NULL;
247 Context *context = userdata;
248 unsigned n_components = 0;
249 Match *m = NULL;
250 Client *c = NULL;
251 char *arg0;
252 uint64_t id;
253 int r;
254
255 assert(bus);
256 assert(message);
257 assert(context);
258
259 r = sd_bus_message_read(message, "s", &arg0);
260 if (r < 0)
261 return r;
262
263 r = bus_kernel_parse_unique_name(message->sender, &id);
264 if (r < 0)
265 return r;
266
267 r = client_acquire(context, id, &c);
268 if (r == -ENOBUFS)
269 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Reached limit of %u clients", CLIENTS_MAX);
270 if (r < 0)
271 return r;
272
273 if (c->n_matches >= MATCHES_MAX) {
274 r = sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Reached limit of %u matches per client", MATCHES_MAX);
275 goto fail;
276 }
277
278 r = bus_match_parse(arg0, &components, &n_components);
279 if (r < 0) {
280 r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_INVALID, "Match rule \"%s\" is not valid", arg0);
281 goto fail;
282 }
283
284 r = match_new(c, components, n_components, &m);
285 if (r < 0)
286 goto fail;
287
288 r = bus_add_match_internal_kernel(bus, id, components, n_components, m->cookie);
289 if (r < 0)
290 goto fail;
291
292 bus_match_parse_free(components, n_components);
293
294 return sd_bus_reply_method_return(message, NULL);
295
296 fail:
297 bus_match_parse_free(components, n_components);
298
299 match_free(m);
300
301 if (c->n_matches <= 0)
302 client_free(c);
303
304 return r;
305 }
306
307 static int driver_remove_match(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
308
309 struct bus_match_component *components = NULL;
310 _cleanup_free_ char *normalized = NULL;
311 Context *context = userdata;
312 unsigned n_components = 0;
313 Client *c = NULL;
314 Match *m = NULL;
315 char *arg0;
316 uint64_t id;
317 int r;
318
319 assert(bus);
320 assert(message);
321 assert(context);
322
323 r = sd_bus_message_read(message, "s", &arg0);
324 if (r < 0)
325 return r;
326
327 r = bus_kernel_parse_unique_name(message->sender, &id);
328 if (r < 0)
329 return r;
330
331 c = hashmap_get(context->clients, &id);
332 if (!c)
333 return sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "You have not registered any matches.");
334
335 r = bus_match_parse(arg0, &components, &n_components);
336 if (r < 0) {
337 r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_INVALID, "Match rule \"%s\" is not valid", arg0);
338 goto finish;
339 }
340
341 normalized = bus_match_to_string(components, n_components);
342 if (!normalized) {
343 r = -ENOMEM;
344 goto finish;
345 }
346
347 m = hashmap_get(c->matches, normalized);
348 if (!m) {
349 r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule \"%s\" not found.");
350 goto finish;
351 }
352
353 bus_remove_match_internal_kernel(bus, id, m->cookie);
354 match_free(m);
355
356 r = sd_bus_reply_method_return(message, NULL);
357
358 finish:
359 bus_match_parse_free(components, n_components);
360
361 if (c->n_matches <= 0)
362 client_free(c);
363
364 return r;
365 }
366
367 static int get_creds(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
368 _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
369 const char *name;
370 int r;
371
372 assert(bus);
373 assert(m);
374 assert(_creds);
375
376 r = sd_bus_message_read(m, "s", &name);
377 if (r < 0)
378 return r;
379
380 assert_return(service_name_is_valid(name), -EINVAL);
381
382 r = sd_bus_get_owner(bus, name, mask, &c);
383 if (r == -ENOENT || r == -ENXIO)
384 return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
385 if (r < 0)
386 return r;
387
388 if ((c->mask & mask) != mask)
389 return -ENOTSUP;
390
391 *_creds = c;
392 c = NULL;
393
394 return 0;
395 }
396
397 static int driver_get_security_context(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
398 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
399 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
400 int r;
401
402 r = get_creds(bus, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, error);
403 if (r < 0)
404 return r;
405
406 r = sd_bus_message_new_method_return(m, &reply);
407 if (r < 0)
408 return r;
409
410 r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
411 if (r < 0)
412 return r;
413
414 return sd_bus_send(bus, reply, NULL);
415 }
416
417 static int driver_get_pid(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
418 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
419 int r;
420
421 r = get_creds(bus, m, SD_BUS_CREDS_PID, &creds, error);
422 if (r < 0)
423 return r;
424
425 return sd_bus_reply_method_return(m, "u", (uint32_t) creds->pid);
426 }
427
428 static int driver_get_user(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
429 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
430 int r;
431
432 r = get_creds(bus, m, SD_BUS_CREDS_UID, &creds, error);
433 if (r < 0)
434 return r;
435
436 return sd_bus_reply_method_return(m, "u", (uint32_t) creds->uid);
437 }
438
439 static int driver_get_name_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
440 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
441 int r;
442
443 r = get_creds(bus, m, SD_BUS_CREDS_UNIQUE_NAME, &creds, error);
444 if (r < 0)
445 return r;
446
447 return sd_bus_reply_method_return(m, "s", creds->unique_name);
448 }
449
450 static int driver_get_id(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
451 sd_id128_t server_id;
452 char buf[SD_ID128_STRING_MAX];
453 int r;
454
455 r = sd_bus_get_server_id(bus, &server_id);
456 if (r < 0)
457 return r;
458
459 return sd_bus_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
460 }
461
462 static int driver_hello(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
463 return sd_bus_reply_method_return(m, "s", m->sender);
464 }
465
466 static int return_strv(sd_bus *bus, sd_bus_message *m, char **l) {
467 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
468 int r;
469
470 r = sd_bus_message_new_method_return(m, &reply);
471 if (r < 0)
472 return r;
473
474 r = sd_bus_message_append_strv(reply, l);
475 if (r < 0)
476 return r;
477
478 return sd_bus_send(bus, reply, NULL);
479 }
480
481 static int driver_list_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
482 _cleanup_strv_free_ char **names = NULL;
483 int r;
484
485 r = sd_bus_list_names(bus, &names, NULL);
486 if (r < 0)
487 return r;
488
489 /* Let's sort the names list to make it stable */
490 strv_sort(names);
491
492 return return_strv(bus, m, names);
493 }
494
495 static int driver_list_activatable_names(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
496 _cleanup_strv_free_ char **names = NULL;
497 int r;
498
499 r = sd_bus_list_names(bus, NULL, &names);
500 if (r < 0)
501 return r;
502
503 /* Let's sort the names list to make it stable */
504 strv_sort(names);
505
506 return return_strv(bus, m, names);
507 }
508
509 static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
510 struct kdbus_cmd_name_list cmd = {};
511 struct kdbus_name_list *name_list;
512 struct kdbus_cmd_name *name;
513 _cleanup_strv_free_ char **owners = NULL;
514 char *arg0;
515 int r;
516
517 r = sd_bus_message_read(m, "s", &arg0);
518 if (r < 0)
519 return r;
520
521 assert_return(service_name_is_valid(arg0), -EINVAL);
522
523 cmd.flags = KDBUS_NAME_LIST_QUEUED;
524
525 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd);
526 if (r < 0)
527 return -errno;
528
529 name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
530
531 KDBUS_ITEM_FOREACH(name, name_list, names) {
532 char *n;
533
534 if (name->size <= sizeof(*name))
535 continue;
536
537 if (!streq(name->name, arg0))
538 continue;
539
540 if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0)
541 return -ENOMEM;
542
543 r = strv_push(&owners, n);
544 if (r < 0) {
545 free(n);
546 return -ENOMEM;
547 }
548 }
549
550 r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd.offset);
551 if (r < 0)
552 return -errno;
553
554 return return_strv(bus, m, owners);
555 }
556
557 static int driver_name_has_owner(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
558 const char *name;
559 int r;
560
561 r = sd_bus_message_read(m, "s", &name);
562 if (r < 0)
563 return r;
564
565 assert_return(service_name_is_valid(name), -EINVAL);
566
567 r = sd_bus_get_owner(bus, name, 0, NULL);
568 if (r < 0 && r != -ENOENT && r != -ENXIO)
569 return r;
570
571 return sd_bus_reply_method_return(m, "b", r >= 0);
572 }
573
574 static int driver_request_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
575 struct kdbus_cmd_name *n;
576 uint32_t flags;
577 size_t size, l;
578 uint64_t id;
579 const char *name;
580 int r;
581
582 r = sd_bus_message_read(m, "su", &name, &flags);
583 if (r < 0)
584 return r;
585
586 assert_return(service_name_is_valid(name), -EINVAL);
587 assert_return((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) == 0, -EINVAL);
588
589 l = strlen(name);
590 size = offsetof(struct kdbus_cmd_name, name) + l + 1;
591 n = alloca0(size);
592 n->size = size;
593 memcpy(n->name, name, l+1);
594 kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
595
596 /* This function is open-coded because we request the name 'on behalf'
597 * of the requesting connection */
598 r = bus_kernel_parse_unique_name(m->sender, &id);
599 if (r < 0)
600 return r;
601
602 n->owner_id = id;
603
604 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
605 if (r < 0) {
606 if (errno == EEXIST)
607 return sd_bus_reply_method_return(m, "u", BUS_NAME_EXISTS);
608 if (errno == EALREADY)
609 return sd_bus_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
610
611 return -errno;
612 }
613
614 if (n->flags & KDBUS_NAME_IN_QUEUE)
615 return sd_bus_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
616
617 return sd_bus_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
618 }
619
620 static int driver_release_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
621 struct kdbus_cmd_name *n;
622 const char *name;
623 size_t l, size;
624 uint64_t id;
625 int r;
626
627 r = sd_bus_message_read(m, "s", &name);
628 if (r < 0)
629 return r;
630
631 assert_return(service_name_is_valid(name), -EINVAL);
632
633 l = strlen(name);
634 size = offsetof(struct kdbus_cmd_name, name) + l + 1;
635 n = alloca0(size);
636 n->size = size;
637 memcpy(n->name, name, l+1);
638
639 /* This function is open-coded because we request the name 'on behalf'
640 * of the requesting connection */
641 r = bus_kernel_parse_unique_name(m->sender, &id);
642 if (r < 0)
643 return r;
644
645 n->owner_id = id;
646
647 r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
648 if (r < 0) {
649 if (errno == ESRCH)
650 return sd_bus_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
651 if (errno == EADDRINUSE)
652 return sd_bus_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
653 return -errno;
654 }
655
656 return sd_bus_reply_method_return(m, "u", BUS_NAME_RELEASED);
657 }
658
659 static int driver_start_service_by_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
660 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
661 _cleanup_strv_free_ char **t = NULL;
662 _cleanup_free_ char *path = NULL;
663 uint32_t flags;
664 char *name, *u;
665 int r;
666
667 r = sd_bus_message_read(m, "su", &name, &flags);
668 if (r < 0)
669 return r;
670
671 assert_return(service_name_is_valid(name), -EINVAL);
672 assert_return(flags == 0, -ENOTSUP);
673
674 r = sd_bus_get_owner(bus, name, 0, NULL);
675 if (r >= 0)
676 return sd_bus_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
677 if (r != -ENOENT)
678 return r;
679
680 u = strappenda(name, ".busname");
681
682 path = unit_dbus_path_from_name(u);
683 if (!path)
684 return -ENOMEM;
685
686 r = sd_bus_get_property_strv(
687 bus,
688 "org.freedesktop.systemd1",
689 path,
690 "org.freedesktop.systemd1.Unit",
691 "Triggers",
692 error,
693 &t);
694 if (r < 0)
695 return r;
696
697 if (!t || !t[0] || t[1])
698 return -EIO;
699
700 r = sd_bus_call_method(
701 bus,
702 "org.freedesktop.systemd1",
703 "/org/freedesktop/systemd1",
704 "org.freedesktop.systemd1.Manager",
705 "StartUnit",
706 error,
707 &reply,
708 "ss",
709 t[0],
710 "replace");
711 if (r < 0)
712 return r;
713
714 return sd_bus_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
715 }
716
717 static int driver_unsupported(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
718 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
719 }
720
721 static const sd_bus_vtable driver_vtable[] = {
722 SD_BUS_VTABLE_START(0),
723 SD_BUS_METHOD("AddMatch", "s", NULL, driver_add_match, SD_BUS_VTABLE_UNPRIVILEGED),
724 SD_BUS_METHOD("GetConnectionSELinuxSecurityContext", "s", "ay", driver_get_security_context, SD_BUS_VTABLE_UNPRIVILEGED),
725 SD_BUS_METHOD("GetConnectionUnixProcessID", "s", "u", driver_get_pid, SD_BUS_VTABLE_UNPRIVILEGED),
726 SD_BUS_METHOD("GetConnectionUnixUser", "s", "u", driver_get_user, SD_BUS_VTABLE_UNPRIVILEGED),
727 SD_BUS_METHOD("GetId", NULL, "s", driver_get_id, SD_BUS_VTABLE_UNPRIVILEGED),
728 SD_BUS_METHOD("GetNameOwner", "s", "s", driver_get_name_owner, SD_BUS_VTABLE_UNPRIVILEGED),
729 SD_BUS_METHOD("Hello", NULL, "s", driver_hello, SD_BUS_VTABLE_UNPRIVILEGED),
730 SD_BUS_METHOD("ListActivatableNames", NULL, "as", driver_list_activatable_names, SD_BUS_VTABLE_UNPRIVILEGED),
731 SD_BUS_METHOD("ListNames", NULL, "as", driver_list_names, SD_BUS_VTABLE_UNPRIVILEGED),
732 SD_BUS_METHOD("ListQueuedOwners", "s", "as", driver_list_queued_owners, SD_BUS_VTABLE_UNPRIVILEGED),
733 SD_BUS_METHOD("NameHasOwner", "s", "b", driver_name_has_owner, SD_BUS_VTABLE_UNPRIVILEGED),
734 SD_BUS_METHOD("ReleaseName", "s", "u", driver_release_name, SD_BUS_VTABLE_UNPRIVILEGED),
735 SD_BUS_METHOD("ReloadConfig", NULL, NULL, driver_unsupported, SD_BUS_VTABLE_DEPRECATED),
736 SD_BUS_METHOD("RemoveMatch", "s", NULL, driver_remove_match, SD_BUS_VTABLE_UNPRIVILEGED),
737 SD_BUS_METHOD("RequestName", "su", "u", driver_request_name, SD_BUS_VTABLE_UNPRIVILEGED),
738 SD_BUS_METHOD("StartServiceByName", "su", "u", driver_start_service_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
739 SD_BUS_METHOD("UpdateActivationEnvironment", "a{ss}", NULL, driver_unsupported, SD_BUS_VTABLE_DEPRECATED),
740 SD_BUS_SIGNAL("NameAcquired", "s", SD_BUS_VTABLE_DEPRECATED),
741 SD_BUS_SIGNAL("NameLost", "s", SD_BUS_VTABLE_DEPRECATED),
742 SD_BUS_SIGNAL("NameOwnerChanged", "sss", 0),
743 SD_BUS_VTABLE_END
744 };
745
746 static int connect_bus(Context *c) {
747 int r;
748
749 assert(c);
750
751 r = sd_bus_default_system(&c->bus);
752 if (r < 0) {
753 log_error("Failed to create bus: %s", strerror(-r));
754 return r;
755 }
756
757 if (!c->bus->is_kernel) {
758 log_error("Not running on kdbus");
759 return -EPERM;
760 }
761
762 r = sd_bus_add_object_vtable(c->bus, "/org/freedesktop/DBus", "org.freedesktop.DBus", driver_vtable, c);
763 if (r < 0) {
764 log_error("Failed to add manager object vtable: %s", strerror(-r));
765 return r;
766 }
767
768 r = sd_bus_request_name(c->bus, "org.freedesktop.DBus", 0);
769 if (r < 0) {
770 log_error("Unable to request name: %s", strerror(-r));
771 return r;
772 }
773
774 r = sd_bus_attach_event(c->bus, c->event, 0);
775 if (r < 0) {
776 log_error("Error while adding bus to event loop: %s", strerror(-r));
777 return r;
778 }
779
780 return 0;
781 }
782
783 static bool check_idle(void *userdata) {
784 Context *c = userdata;
785 assert(c);
786
787 return hashmap_isempty(c->clients);
788 }
789
790 int main(int argc, char *argv[]) {
791 Context context = {};
792 Client *c;
793 int r;
794
795 log_set_target(LOG_TARGET_AUTO);
796 log_parse_environment();
797 log_open();
798
799 if (argc != 1) {
800 log_error("This program takes no arguments.");
801 r = -EINVAL;
802 goto finish;
803 }
804
805 r = sd_event_default(&context.event);
806 if (r < 0) {
807 log_error("Failed to allocate event loop: %s", strerror(-r));
808 goto finish;
809 }
810
811 sd_event_set_watchdog(context.event, true);
812
813 r = connect_bus(&context);
814 if (r < 0)
815 goto finish;
816
817 r = bus_event_loop_with_idle(context.event, context.bus, "org.freedesktop.DBus", DEFAULT_EXIT_USEC, check_idle, &context);
818 if (r < 0) {
819 log_error("Failed to run event loop: %s", strerror(-r));
820 goto finish;
821 }
822
823 finish:
824 while ((c = hashmap_first(context.clients)))
825 client_free(c);
826
827 sd_bus_unref(context.bus);
828 sd_event_unref(context.event);
829
830 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
831
832 }