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);
51 static void busname_done(Unit *u) {
52 BusName *n = BUSNAME(u);
59 unit_ref_unset(&n->service);
61 n->event_source = sd_event_source_unref(n->event_source);
62 n->starter_fd = safe_close(n->starter_fd);
65 static int busname_add_default_default_dependencies(BusName *n) {
70 r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true);
74 if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) {
75 r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
80 return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
83 static int busname_add_extras(BusName *n) {
90 n->name = unit_name_to_prefix(u->id);
95 if (!u->description) {
96 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);
117 if (u->default_dependencies) {
118 r = busname_add_default_default_dependencies(n);
126 static int busname_verify(BusName *n) {
131 if (UNIT(n)->load_state != UNIT_LOADED)
134 if (!service_name_is_valid(n->name)) {
135 log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
139 e = strappenda(n->name, ".busname");
140 if (!unit_has_name(UNIT(n), e)) {
141 log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
148 static int busname_load(Unit *u) {
149 BusName *n = BUSNAME(u);
153 assert(u->load_state == UNIT_STUB);
155 r = unit_load_fragment_and_dropin(u);
159 if (u->load_state == UNIT_LOADED) {
160 /* This is a new unit? Then let's add in some extras */
161 r = busname_add_extras(n);
166 return busname_verify(n);
169 static void busname_dump(Unit *u, FILE *f, const char *prefix) {
170 BusName *n = BUSNAME(u);
176 "%sBus Name State: %s\n"
181 prefix, busname_state_to_string(n->state),
182 prefix, busname_result_to_string(n->result),
184 prefix, yes_no(n->activating),
185 prefix, yes_no(n->accept_fd));
188 static void busname_unwatch_fd(BusName *n) {
193 if (n->event_source) {
194 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_OFF);
196 log_debug_unit(UNIT(n)->id, "Failed to disable event source.");
200 static void busname_close_fd(BusName *n) {
203 busname_unwatch_fd(n);
205 if (n->starter_fd <= 0)
208 n->starter_fd = safe_close(n->starter_fd);
211 static int busname_watch_fd(BusName *n) {
216 if (n->starter_fd < 0)
220 r = sd_event_source_set_enabled(n->event_source, SD_EVENT_ON);
222 r = sd_event_add_io(UNIT(n)->manager->event, &n->event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
224 log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r));
225 busname_unwatch_fd(n);
232 static int busname_open_fd(BusName *n) {
235 if (n->starter_fd >= 0)
238 n->starter_fd = bus_kernel_create_starter(
239 UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
240 n->name, n->activating, n->accept_fd, n->policy);
242 if (n->starter_fd < 0) {
243 log_warning_unit(UNIT(n)->id, "Failed to create starter fd: %s", strerror(-n->starter_fd));
244 return n->starter_fd;
250 static void busname_set_state(BusName *n, BusNameState state) {
251 BusNameState old_state;
254 old_state = n->state;
257 if (state != BUSNAME_LISTENING)
258 busname_unwatch_fd(n);
260 if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING))
263 if (state != old_state)
264 log_debug_unit(UNIT(n)->id, "%s changed %s -> %s",
265 UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
267 unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
270 static int busname_coldplug(Unit *u) {
271 BusName *n = BUSNAME(u);
275 assert(n->state == BUSNAME_DEAD);
277 if (n->deserialized_state == n->state)
280 if (IN_SET(n->deserialized_state, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING)) {
281 r = busname_open_fd(n);
286 if (n->deserialized_state == BUSNAME_LISTENING) {
287 r = busname_watch_fd(n);
292 busname_set_state(n, n->deserialized_state);
296 static void busname_enter_dead(BusName *n, BusNameResult f) {
299 if (f != BUSNAME_SUCCESS)
302 busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
305 static void busname_enter_listening(BusName *n) {
310 r = busname_open_fd(n);
312 log_warning_unit(UNIT(n)->id, "%s failed to %s: %s", UNIT(n)->id,
313 n->activating ? "listen on bus name" : "register policy for name",
319 r = busname_watch_fd(n);
321 log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r));
325 busname_set_state(n, BUSNAME_LISTENING);
327 busname_set_state(n, BUSNAME_REGISTERED);
332 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
335 static void busname_enter_running(BusName *n) {
336 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
337 bool pending = false;
347 /* We don't take conenctions anymore if we are supposed to
348 * shut down anyway */
350 if (unit_stop_pending(UNIT(n))) {
351 log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
353 /* Flush all queued activation reqeuest by closing and reopening the connection */
354 bus_kernel_drop_one(n->starter_fd);
356 busname_enter_listening(n);
360 /* If there's already a start pending don't bother to do
362 SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
363 if (unit_active_or_pending(other)) {
369 r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
374 busname_set_state(n, BUSNAME_RUNNING);
378 log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
379 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
382 static int busname_start(Unit *u) {
383 BusName *n = BUSNAME(u);
387 if (n->activating && UNIT_ISSET(n->service)) {
390 service = SERVICE(UNIT_DEREF(n->service));
392 if (UNIT(service)->load_state != UNIT_LOADED) {
393 log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
398 assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
400 n->result = BUSNAME_SUCCESS;
401 busname_enter_listening(n);
406 static int busname_stop(Unit *u) {
407 BusName *n = BUSNAME(u);
410 assert(IN_SET(n->state, BUSNAME_REGISTERED, BUSNAME_LISTENING, BUSNAME_RUNNING));
412 busname_enter_dead(n, BUSNAME_SUCCESS);
416 static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
417 BusName *n = BUSNAME(u);
423 unit_serialize_item(u, f, "state", busname_state_to_string(n->state));
424 unit_serialize_item(u, f, "result", busname_result_to_string(n->result));
426 if (n->starter_fd >= 0) {
429 copy = fdset_put_dup(fds, n->starter_fd);
433 unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
439 static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
440 BusName *n = BUSNAME(u);
446 if (streq(key, "state")) {
449 state = busname_state_from_string(value);
451 log_debug_unit(u->id, "Failed to parse state value %s", value);
453 n->deserialized_state = state;
455 } else if (streq(key, "result")) {
458 f = busname_result_from_string(value);
460 log_debug_unit(u->id, "Failed to parse result value %s", value);
461 else if (f != BUSNAME_SUCCESS)
464 } else if (streq(key, "starter-fd")) {
467 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
468 log_debug_unit(u->id, "Failed to parse starter fd value %s", value);
470 safe_close(n->starter_fd);
471 n->starter_fd = fdset_remove(fds, fd);
474 log_debug_unit(u->id, "Unknown serialization key '%s'", key);
479 _pure_ static UnitActiveState busname_active_state(Unit *u) {
482 return state_translation_table[BUSNAME(u)->state];
485 _pure_ static const char *busname_sub_state_to_string(Unit *u) {
488 return busname_state_to_string(BUSNAME(u)->state);
491 static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
492 BusName *n = userdata;
497 if (n->state != BUSNAME_LISTENING)
500 log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
502 if (revents != EPOLLIN) {
503 log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
504 UNIT(n)->id, revents);
508 busname_enter_running(n);
512 busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
516 static void busname_reset_failed(Unit *u) {
517 BusName *n = BUSNAME(u);
521 if (n->state == BUSNAME_FAILED)
522 busname_set_state(n, BUSNAME_DEAD);
524 n->result = BUSNAME_SUCCESS;
527 static void busname_trigger_notify(Unit *u, Unit *other) {
528 BusName *n = BUSNAME(u);
534 if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
537 if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
542 if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
543 busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
544 else if (IN_SET(s->state,
545 SERVICE_DEAD, SERVICE_FAILED,
546 SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
547 SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
548 SERVICE_AUTO_RESTART))
549 busname_enter_listening(n);
552 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
553 [BUSNAME_DEAD] = "dead",
554 [BUSNAME_REGISTERED] = "registered",
555 [BUSNAME_LISTENING] = "listening",
556 [BUSNAME_RUNNING] = "running",
557 [BUSNAME_FAILED] = "failed"
560 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
562 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
563 [BUSNAME_SUCCESS] = "success",
564 [BUSNAME_FAILURE_RESOURCES] = "resources",
565 [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
568 DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
570 static const char* const busname_policy_access_table[_BUSNAME_POLICY_ACCESS_MAX] = {
571 [BUSNAME_POLICY_ACCESS_SEE] = "see",
572 [BUSNAME_POLICY_ACCESS_TALK] = "talk",
573 [BUSNAME_POLICY_ACCESS_OWN] = "own",
576 DEFINE_STRING_TABLE_LOOKUP(busname_policy_access, BusNamePolicyAccess);
578 const UnitVTable busname_vtable = {
579 .object_size = sizeof(BusName),
585 .private_section = "BusName",
587 .init = busname_init,
588 .done = busname_done,
589 .load = busname_load,
591 .coldplug = busname_coldplug,
593 .dump = busname_dump,
595 .start = busname_start,
596 .stop = busname_stop,
598 .serialize = busname_serialize,
599 .deserialize_item = busname_deserialize_item,
601 .active_state = busname_active_state,
602 .sub_state_to_string = busname_sub_state_to_string,
604 .trigger_notify = busname_trigger_notify,
606 .reset_failed = busname_reset_failed,
608 .bus_interface = "org.freedesktop.systemd1.BusName",
609 .bus_vtable = bus_busname_vtable,
611 .status_message_formats = {
612 .finished_start_job = {
613 [JOB_DONE] = "Listening on %s.",
614 [JOB_FAILED] = "Failed to listen on %s.",
615 [JOB_DEPENDENCY] = "Dependency failed for %s.",
616 [JOB_TIMEOUT] = "Timed out starting %s.",
618 .finished_stop_job = {
619 [JOB_DONE] = "Closed %s.",
620 [JOB_FAILED] = "Failed stopping %s.",
621 [JOB_TIMEOUT] = "Timed out stopping %s.",