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_REGISTERED] = UNIT_ACTIVE,
33 [BUSNAME_LISTENING] = UNIT_ACTIVE,
34 [BUSNAME_RUNNING] = UNIT_ACTIVE,
35 [BUSNAME_FAILED] = UNIT_FAILED
38 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
40 static void busname_init(Unit *u) {
41 BusName *n = BUSNAME(u);
44 assert(u->load_state == UNIT_STUB);
50 static void busname_done(Unit *u) {
51 BusName *n = BUSNAME(u);
58 unit_ref_unset(&n->service);
60 n->event_source = sd_event_source_unref(n->event_source);
61 n->starter_fd = safe_close(n->starter_fd);
64 static int busname_add_default_default_dependencies(BusName *n) {
69 r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true);
73 if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) {
74 r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
79 return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
82 static int busname_add_extras(BusName *n) {
89 n->name = unit_name_to_prefix(u->id);
94 if (!u->description) {
95 r = unit_set_description(u, n->name);
101 if (!UNIT_DEREF(n->service)) {
104 r = unit_load_related_unit(u, ".service", &x);
108 unit_ref_set(&n->service, x);
111 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);
125 static int busname_verify(BusName *n) {
130 if (UNIT(n)->load_state != UNIT_LOADED)
133 if (!service_name_is_valid(n->name)) {
134 log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
138 e = strappenda(n->name, ".busname");
139 if (!unit_has_name(UNIT(n), e)) {
140 log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
147 static int busname_load(Unit *u) {
148 BusName *n = BUSNAME(u);
152 assert(u->load_state == UNIT_STUB);
154 r = unit_load_fragment_and_dropin(u);
158 if (u->load_state == UNIT_LOADED) {
159 /* This is a new unit? Then let's add in some extras */
160 r = busname_add_extras(n);
165 return busname_verify(n);
168 static void busname_dump(Unit *u, FILE *f, const char *prefix) {
169 BusName *n = BUSNAME(u);
175 "%sBus Name State: %s\n"
180 prefix, busname_state_to_string(n->state),
181 prefix, busname_result_to_string(n->result),
183 prefix, yes_no(n->activating),
184 prefix, yes_no(n->accept_fd));
187 static void busname_unwatch_fd(BusName *n) {
192 if (n->event_source) {
193 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_OFF);
195 log_debug_unit(UNIT(n)->id, "Failed to disable event source.");
199 static void busname_close_fd(BusName *n) {
202 busname_unwatch_fd(n);
204 if (n->starter_fd <= 0)
207 n->starter_fd = safe_close(n->starter_fd);
210 static int busname_watch_fd(BusName *n) {
215 if (n->starter_fd < 0)
219 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_ON);
221 r = sd_event_add_io(UNIT(n)->manager->event, &n->event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
223 log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r));
224 busname_unwatch_fd(n);
231 static int busname_open_fd(BusName *n) {
234 if (n->starter_fd >= 0)
237 n->starter_fd = bus_kernel_create_starter(
238 UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
239 n->name, n->activating, n->accept_fd, n->policy);
241 if (n->starter_fd < 0) {
242 log_warning_unit(UNIT(n)->id, "Failed to create starter fd: %s", strerror(-n->starter_fd));
243 return n->starter_fd;
249 static void busname_set_state(BusName *n, BusNameState state) {
250 BusNameState old_state;
253 old_state = n->state;
256 if (state != BUSNAME_LISTENING)
257 busname_unwatch_fd(n);
259 if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING))
262 if (state != old_state)
263 log_debug_unit(UNIT(n)->id, "%s changed %s -> %s",
264 UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
266 unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
269 static int busname_coldplug(Unit *u) {
270 BusName *n = BUSNAME(u);
274 assert(n->state == BUSNAME_DEAD);
276 if (n->deserialized_state == n->state)
279 if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING)) {
280 r = busname_open_fd(n);
285 if (n->deserialized_state == BUSNAME_LISTENING) {
286 r = busname_watch_fd(n);
291 busname_set_state(n, n->deserialized_state);
295 static void busname_enter_dead(BusName *n, BusNameResult f) {
298 if (f != BUSNAME_SUCCESS)
301 busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
304 static void busname_enter_listening(BusName *n) {
309 r = busname_open_fd(n);
311 log_warning_unit(UNIT(n)->id, "%s failed to %s: %s", UNIT(n)->id,
312 n->activating ? "listen on bus name" : "register policy for name",
318 r = busname_watch_fd(n);
320 log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r));
324 busname_set_state(n, BUSNAME_LISTENING);
326 busname_set_state(n, BUSNAME_REGISTERED);
331 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
334 static void busname_enter_running(BusName *n) {
335 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
336 bool pending = false;
346 /* We don't take conenctions anymore if we are supposed to
347 * shut down anyway */
349 if (unit_stop_pending(UNIT(n))) {
350 log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
352 /* Flush all queued activation reqeuest by closing and reopening the connection */
353 bus_kernel_drop_one(n->starter_fd);
355 busname_enter_listening(n);
359 /* If there's already a start pending don't bother to do
361 SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
362 if (unit_active_or_pending(other)) {
368 r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
373 busname_set_state(n, BUSNAME_RUNNING);
377 log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
378 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
381 static int busname_start(Unit *u) {
382 BusName *n = BUSNAME(u);
386 if (n->activating && UNIT_ISSET(n->service)) {
389 service = SERVICE(UNIT_DEREF(n->service));
391 if (UNIT(service)->load_state != UNIT_LOADED) {
392 log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
397 assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
399 n->result = BUSNAME_SUCCESS;
400 busname_enter_listening(n);
405 static int busname_stop(Unit *u) {
406 BusName *n = BUSNAME(u);
409 assert(IN_SET(n->state, BUSNAME_REGISTERED, BUSNAME_LISTENING, BUSNAME_RUNNING));
411 busname_enter_dead(n, BUSNAME_SUCCESS);
415 static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
416 BusName *n = BUSNAME(u);
422 unit_serialize_item(u, f, "state", busname_state_to_string(n->state));
423 unit_serialize_item(u, f, "result", busname_result_to_string(n->result));
425 if (n->starter_fd >= 0) {
428 copy = fdset_put_dup(fds, n->starter_fd);
432 unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
438 static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
439 BusName *n = BUSNAME(u);
445 if (streq(key, "state")) {
448 state = busname_state_from_string(value);
450 log_debug_unit(u->id, "Failed to parse state value %s", value);
452 n->deserialized_state = state;
454 } else if (streq(key, "result")) {
457 f = busname_result_from_string(value);
459 log_debug_unit(u->id, "Failed to parse result value %s", value);
460 else if (f != BUSNAME_SUCCESS)
463 } else if (streq(key, "starter-fd")) {
466 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
467 log_debug_unit(u->id, "Failed to parse starter fd value %s", value);
469 safe_close(n->starter_fd);
470 n->starter_fd = fdset_remove(fds, fd);
473 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
478 _pure_ static UnitActiveState busname_active_state(Unit *u) {
481 return state_translation_table[BUSNAME(u)->state];
484 _pure_ static const char *busname_sub_state_to_string(Unit *u) {
487 return busname_state_to_string(BUSNAME(u)->state);
490 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
491 BusName *n = userdata;
496 if (n->state != BUSNAME_LISTENING)
499 log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
501 if (revents != EPOLLIN) {
502 log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
503 UNIT(n)->id, revents);
507 busname_enter_running(n);
511 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
515 static void busname_reset_failed(Unit *u) {
516 BusName *n = BUSNAME(u);
520 if (n->state == BUSNAME_FAILED)
521 busname_set_state(n, BUSNAME_DEAD);
523 n->result = BUSNAME_SUCCESS;
526 static void busname_trigger_notify(Unit *u, Unit *other) {
527 BusName *n = BUSNAME(u);
533 if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
536 if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
541 if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
542 busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
543 else if (IN_SET(s->state,
544 SERVICE_DEAD, SERVICE_FAILED,
545 SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
546 SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
547 SERVICE_AUTO_RESTART))
548 busname_enter_listening(n);
551 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
552 [BUSNAME_DEAD] = "dead",
553 [BUSNAME_REGISTERED] = "registered",
554 [BUSNAME_LISTENING] = "listening",
555 [BUSNAME_RUNNING] = "running",
556 [BUSNAME_FAILED] = "failed"
559 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
561 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
562 [BUSNAME_SUCCESS] = "success",
563 [BUSNAME_FAILURE_RESOURCES] = "resources",
564 [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
567 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
569 static const char* const busname_policy_access_table[_BUSNAME_POLICY_ACCESS_MAX] = {
570 [BUSNAME_POLICY_ACCESS_SEE] = "see",
571 [BUSNAME_POLICY_ACCESS_TALK] = "talk",
572 [BUSNAME_POLICY_ACCESS_OWN] = "own",
575 DEFINE_STRING_TABLE_LOOKUP(busname_policy_access, BusNamePolicyAccess);
577 const UnitVTable busname_vtable = {
578 .object_size = sizeof(BusName),
584 .private_section = "BusName",
586 .init = busname_init,
587 .done = busname_done,
588 .load = busname_load,
590 .coldplug = busname_coldplug,
592 .dump = busname_dump,
594 .start = busname_start,
595 .stop = busname_stop,
597 .serialize = busname_serialize,
598 .deserialize_item = busname_deserialize_item,
600 .active_state = busname_active_state,
601 .sub_state_to_string = busname_sub_state_to_string,
603 .trigger_notify = busname_trigger_notify,
605 .reset_failed = busname_reset_failed,
607 .bus_interface = "org.freedesktop.systemd1.BusName",
608 .bus_vtable = bus_busname_vtable,
610 .status_message_formats = {
611 .finished_start_job = {
612 [JOB_DONE] = "Listening on %s.",
613 [JOB_FAILED] = "Failed to listen on %s.",
614 [JOB_DEPENDENCY] = "Dependency failed for %s.",
615 [JOB_TIMEOUT] = "Timed out starting %s.",
617 .finished_stop_job = {
618 [JOB_DONE] = "Closed %s.",
619 [JOB_FAILED] = "Failed stopping %s.",
620 [JOB_TIMEOUT] = "Timed out stopping %s.",