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 "bus-kernel.h"
24 #include "bus-internal.h"
27 #include "dbus-busname.h"
30 static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
31 [BUSNAME_DEAD] = UNIT_INACTIVE,
32 [BUSNAME_LISTENING] = UNIT_ACTIVE,
33 [BUSNAME_RUNNING] = UNIT_ACTIVE,
34 [BUSNAME_FAILED] = UNIT_FAILED
37 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
39 static void busname_init(Unit *u) {
40 BusName *n = BUSNAME(u);
43 assert(u->load_state == UNIT_STUB);
48 static void busname_done(Unit *u) {
49 BusName *n = BUSNAME(u);
56 unit_ref_unset(&n->service);
58 n->event_source = sd_event_source_unref(n->event_source);
60 if (n->starter_fd >= 0) {
61 close_nointr_nofail(n->starter_fd);
66 static int busname_add_default_default_dependencies(BusName *n) {
71 r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true);
75 if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) {
76 r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
81 return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
84 static int busname_add_extras(BusName *n) {
91 n->name = unit_name_to_prefix(u->id);
96 if (!u->description) {
97 r = unit_set_description(u, n->name);
102 if (!UNIT_DEREF(n->service)) {
105 r = unit_load_related_unit(u, ".service", &x);
109 unit_ref_set(&n->service, x);
112 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(n->service), true);
116 if (u->default_dependencies) {
117 r = busname_add_default_default_dependencies(n);
127 static int busname_verify(BusName *n) {
132 if (UNIT(n)->load_state != UNIT_LOADED)
135 if (!service_name_is_valid(n->name)) {
136 log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
140 e = strappenda(n->name, ".busname");
141 if (!unit_has_name(UNIT(n), e)) {
142 log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
149 static int busname_load(Unit *u) {
150 BusName *n = BUSNAME(u);
154 assert(u->load_state == UNIT_STUB);
156 r = unit_load_fragment_and_dropin(u);
160 if (u->load_state == UNIT_LOADED) {
161 /* This is a new unit? Then let's add in some extras */
162 r = busname_add_extras(n);
167 return busname_verify(n);
170 static void busname_dump(Unit *u, FILE *f, const char *prefix) {
171 BusName *n = BUSNAME(u);
177 "%sBus Name State: %s\n"
180 prefix, busname_state_to_string(n->state),
181 prefix, busname_result_to_string(n->result),
185 static void busname_unwatch_fd(BusName *n) {
190 if (n->event_source) {
191 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_OFF);
193 log_debug_unit(UNIT(n)->id, "Failed to disable event source.");
197 static void busname_close_fd(BusName *n) {
200 if (n->starter_fd <= 0)
203 close_nointr_nofail(n->starter_fd);
207 static int busname_watch_fd(BusName *n) {
212 if (n->starter_fd < 0)
216 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_ON);
218 r = sd_event_add_io(UNIT(n)->manager->event, n->starter_fd, EPOLLIN, busname_dispatch_io, n, &n->event_source);
220 log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r));
221 busname_unwatch_fd(n);
228 static int busname_open_fd(BusName *n) {
231 if (n->starter_fd >= 0)
234 n->starter_fd = bus_kernel_create_starter(UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user", n->name);
235 if (n->starter_fd < 0) {
236 log_warning_unit(UNIT(n)->id, "Failed to create starter fd: %s", strerror(-n->starter_fd));
237 return n->starter_fd;
243 static void busname_set_state(BusName *n, BusNameState state) {
244 BusNameState old_state;
247 old_state = n->state;
250 if (state != BUSNAME_LISTENING)
251 busname_unwatch_fd(n);
253 if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_RUNNING))
256 if (state != old_state)
257 log_debug_unit(UNIT(n)->id, "%s changed %s -> %s",
258 UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
260 unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
263 static int busname_coldplug(Unit *u) {
264 BusName *n = BUSNAME(u);
268 assert(n->state == BUSNAME_DEAD);
270 if (n->deserialized_state == n->state)
273 if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_RUNNING)) {
274 r = busname_open_fd(n);
279 if (n->deserialized_state == BUSNAME_LISTENING) {
280 r = busname_watch_fd(n);
285 busname_set_state(n, n->deserialized_state);
289 static void busname_enter_dead(BusName *n, BusNameResult f) {
292 if (f != BUSNAME_SUCCESS)
295 busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
298 static void busname_enter_listening(BusName *n) {
303 r = busname_open_fd(n);
305 log_warning_unit(UNIT(n)->id, "%s failed to listen on bus names: %s", UNIT(n)->id, strerror(-r));
309 r = busname_watch_fd(n);
311 log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r));
315 busname_set_state(n, BUSNAME_LISTENING);
319 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
322 static void busname_enter_running(BusName *n) {
323 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
324 bool pending = false;
331 /* We don't take conenctions anymore if we are supposed to
332 * shut down anyway */
334 if (unit_stop_pending(UNIT(n))) {
335 log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
339 /* If there's already a start pending don't bother to do
341 SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
342 if (unit_active_or_pending(other)) {
348 r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
353 busname_set_state(n, BUSNAME_RUNNING);
357 log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
358 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
361 static int busname_start(Unit *u) {
362 BusName *n = BUSNAME(u);
366 if (UNIT_ISSET(n->service)) {
369 service = SERVICE(UNIT_DEREF(n->service));
371 if (UNIT(service)->load_state != UNIT_LOADED) {
372 log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
377 assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
379 n->result = BUSNAME_SUCCESS;
380 busname_enter_listening(n);
385 static int busname_stop(Unit *u) {
386 BusName *n = BUSNAME(u);
389 assert(n->state == BUSNAME_LISTENING || n->state == BUSNAME_RUNNING);
391 busname_enter_dead(n, BUSNAME_SUCCESS);
395 static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
396 BusName *n = BUSNAME(u);
402 unit_serialize_item(u, f, "state", busname_state_to_string(n->state));
403 unit_serialize_item(u, f, "result", busname_result_to_string(n->result));
405 if (n->starter_fd >= 0) {
408 copy = fdset_put_dup(fds, n->starter_fd);
412 unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
418 static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
419 BusName *n = BUSNAME(u);
425 if (streq(key, "state")) {
428 state = busname_state_from_string(value);
430 log_debug_unit(u->id, "Failed to parse state value %s", value);
432 n->deserialized_state = state;
434 } else if (streq(key, "result")) {
437 f = busname_result_from_string(value);
439 log_debug_unit(u->id, "Failed to parse result value %s", value);
440 else if (f != BUSNAME_SUCCESS)
443 } else if (streq(key, "starter-fd")) {
446 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
447 log_debug_unit(u->id, "Failed to parse starter fd value %s", value);
449 if (n->starter_fd >= 0)
450 close_nointr_nofail(n->starter_fd);
451 n->starter_fd = fdset_remove(fds, fd);
454 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
459 _pure_ static UnitActiveState busname_active_state(Unit *u) {
462 return state_translation_table[BUSNAME(u)->state];
465 _pure_ static const char *busname_sub_state_to_string(Unit *u) {
468 return busname_state_to_string(BUSNAME(u)->state);
471 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
472 BusName *n = userdata;
477 if (n->state != BUSNAME_LISTENING)
480 log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
482 if (revents != EPOLLIN) {
483 log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
484 UNIT(n)->id, revents);
488 busname_enter_running(n);
492 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
496 static void busname_reset_failed(Unit *u) {
497 BusName *n = BUSNAME(u);
501 if (n->state == BUSNAME_FAILED)
502 busname_set_state(n, BUSNAME_DEAD);
504 n->result = BUSNAME_SUCCESS;
507 static void busname_trigger_notify(Unit *u, Unit *other) {
508 BusName *n = BUSNAME(u);
514 if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
517 if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
522 if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
523 busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
524 else if (IN_SET(s->state,
525 SERVICE_DEAD, SERVICE_FAILED,
526 SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
527 SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
528 SERVICE_AUTO_RESTART))
529 busname_enter_listening(n);
532 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
533 [BUSNAME_DEAD] = "dead",
534 [BUSNAME_LISTENING] = "listening",
535 [BUSNAME_RUNNING] = "running",
536 [BUSNAME_FAILED] = "failed"
539 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
541 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
542 [BUSNAME_SUCCESS] = "success",
543 [BUSNAME_FAILURE_RESOURCES] = "resources",
546 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
548 const UnitVTable busname_vtable = {
549 .object_size = sizeof(BusName),
555 .private_section = "BusName",
557 .init = busname_init,
558 .done = busname_done,
559 .load = busname_load,
561 .coldplug = busname_coldplug,
563 .dump = busname_dump,
565 .start = busname_start,
566 .stop = busname_stop,
568 .serialize = busname_serialize,
569 .deserialize_item = busname_deserialize_item,
571 .active_state = busname_active_state,
572 .sub_state_to_string = busname_sub_state_to_string,
574 .trigger_notify = busname_trigger_notify,
576 .reset_failed = busname_reset_failed,
578 .bus_interface = "org.freedesktop.systemd1.BusName",
579 .bus_vtable = bus_busname_vtable,
580 .bus_changing_properties = bus_busname_changing_properties,
582 .status_message_formats = {
583 .finished_start_job = {
584 [JOB_DONE] = "Listening on %s.",
585 [JOB_FAILED] = "Failed to listen on %s.",
586 [JOB_DEPENDENCY] = "Dependency failed for %s.",
587 [JOB_TIMEOUT] = "Timed out starting %s.",
589 .finished_stop_job = {
590 [JOB_DONE] = "Closed %s.",
591 [JOB_FAILED] = "Failed stopping %s.",
592 [JOB_TIMEOUT] = "Timed out stopping %s.",