X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=service.c;h=c85c6f572a62b109c11974ad8d20a307a0fd8dac;hp=96e9d83ad90902d5e59d927a195fd9f28211b4de;hb=8d567588cad053f79abe603ab113e1b85a92f1da;hpb=4f2d528d3bb25cebf8d3ebe83d8193ab4016cb90 diff --git a/service.c b/service.c index 96e9d83ad..c85c6f572 100644 --- a/service.c +++ b/service.c @@ -118,6 +118,12 @@ static void service_done(Unit *u) { service_unwatch_main_pid(s); service_unwatch_control_pid(s); + if (s->bus_name) { + unit_unwatch_bus_name(UNIT(u), s->bus_name); + free(s->bus_name); + s->bus_name = NULL; + } + service_close_socket_fd(s); unit_unwatch_timer(u, &s->timer_watch); @@ -712,36 +718,36 @@ static int service_load_sysv(Service *s) { return 0; } +static int service_add_bus_name(Service *s) { + char *n; + int r; + + assert(s); + assert(s->bus_name); + + if (asprintf(&n, "dbus-%s.service", s->bus_name) < 0) + return 0; + + r = unit_merge_by_name(UNIT(s), n); + free(n); + + return r; +} + static void service_init(Unit *u) { Service *s = SERVICE(u); assert(u); assert(u->meta.load_state == UNIT_STUB); - s->type = 0; - s->restart = 0; - s->timeout_usec = DEFAULT_TIMEOUT_USEC; s->restart_usec = DEFAULT_RESTART_USEC; - - exec_context_init(&s->exec_context); - s->timer_watch.type = WATCH_INVALID; - - s->state = SERVICE_DEAD; - s->sysv_start_priority = -1; - s->permissions_start_only = false; - s->root_directory_start_only = false; - s->valid_no_process = false; - s->kill_mode = 0; - s->sysv_has_lsb = false; - s->main_pid = s->control_pid = 0; - s->main_pid_known = false; - s->failure = false; - s->socket_fd = -1; + exec_context_init(&s->exec_context); + RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5); } @@ -756,6 +762,11 @@ static int service_verify(Service *s) { return -EINVAL; } + if (s->type == SERVICE_DBUS && !s->bus_name) { + log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->meta.id); + return -EINVAL; + } + return 0; } @@ -793,6 +804,14 @@ static int service_load(Unit *u) { if ((r = sysv_chkconfig_order(s)) < 0) return r; + + if (s->bus_name) { + if ((r = service_add_bus_name(s)) < 0) + return r; + + if ((r = unit_watch_bus_name(u, s->bus_name)) < 0) + return r; + } } return service_verify(s); @@ -839,6 +858,13 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { "%sPIDFile: %s\n", prefix, s->pid_file); + if (s->bus_name) + fprintf(f, + "%sBusName: %s\n" + "%sBus Name Good: %s\n", + prefix, s->bus_name, + prefix, yes_no(s->bus_name_good)); + exec_context_dump(&s->exec_context, f, prefix); for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) { @@ -944,7 +970,8 @@ static int service_get_sockets(Service *s, Set **_set) { p = manager_get_unit(UNIT(s)->meta.manager, k); free(k); - if (!p) continue; + if (!p) + continue; if ((r = set_put(set, p)) < 0) goto fail; @@ -1373,7 +1400,9 @@ static void service_enter_running(Service *s, bool success) { if (!success) s->failure = true; - if (main_pid_good(s) != 0 && cgroup_good(s) != 0) + if (main_pid_good(s) != 0 && + cgroup_good(s) != 0 && + (s->bus_name_good || s->type != SERVICE_DBUS)) service_set_state(s, SERVICE_RUNNING); else if (s->valid_no_process) service_set_state(s, SERVICE_EXITED); @@ -1425,7 +1454,7 @@ static void service_enter_start(Service *s) { if ((r = service_spawn(s, s->exec_command[SERVICE_EXEC_START], - s->type == SERVICE_FORKING, + s->type == SERVICE_FORKING || s->type == SERVICE_DBUS, true, true, true, @@ -1451,15 +1480,18 @@ static void service_enter_start(Service *s) { s->control_command = s->exec_command[SERVICE_EXEC_START]; service_set_state(s, SERVICE_START); - } else if (s->type == SERVICE_FINISH) { + } else if (s->type == SERVICE_FINISH || + s->type == SERVICE_DBUS) { /* For finishing services we wait until the start * process exited, too, but it is our main process. */ + /* For D-Bus services we know the main pid right away, + * but wait for the bus name to appear on the bus. */ + s->main_pid = pid; s->main_pid_known = true; - s->control_command = s->exec_command[SERVICE_EXEC_START]; service_set_state(s, SERVICE_START); } else assert_not_reached("Unknown service type"); @@ -2046,6 +2078,72 @@ finish: return r; } +static void service_bus_name_owner_change( + Unit *u, + const char *name, + const char *old_owner, + const char *new_owner) { + + Service *s = SERVICE(u); + + assert(s); + assert(name); + + assert(streq(s->bus_name, name)); + assert(old_owner || new_owner); + + if (old_owner && new_owner) + log_debug("%s's D-Bus name %s changed owner from %s to %s", u->meta.id, name, old_owner, new_owner); + else if (old_owner) + log_debug("%s's D-Bus name %s no longer registered by %s", u->meta.id, name, old_owner); + else + log_debug("%s's D-Bus name %s now registered by %s", u->meta.id, name, new_owner); + + s->bus_name_good = !!new_owner; + + if (s->type == SERVICE_DBUS) { + + /* service_enter_running() will figure out what to + * do */ + if (s->state == SERVICE_RUNNING) + service_enter_running(s, true); + else if (s->state == SERVICE_START && new_owner) + service_enter_start_post(s); + + } else if (new_owner && + s->main_pid <= 0 && + (s->state == SERVICE_START || + s->state == SERVICE_START_POST || + s->state == SERVICE_RUNNING || + s->state == SERVICE_RELOAD)) { + + /* Try to acquire PID from bus service */ + log_debug("Trying to acquire PID from D-Bus name..."); + + bus_query_pid(u->meta.manager, name); + } +} + +static void service_bus_query_pid_done( + Unit *u, + const char *name, + pid_t pid) { + + Service *s = SERVICE(u); + + assert(s); + assert(name); + + log_debug("%s's D-Bus name %s is now owned by process %u", u->meta.id, name, (unsigned) pid); + + if (s->main_pid <= 0 && + (s->state == SERVICE_START || + s->state == SERVICE_START_POST || + s->state == SERVICE_RUNNING || + s->state == SERVICE_RELOAD)) + s->main_pid = pid; +} + int service_set_socket_fd(Service *s, int fd) { assert(s); assert(fd >= 0); @@ -2098,7 +2196,8 @@ DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart); static const char* const service_type_table[_SERVICE_TYPE_MAX] = { [SERVICE_FORKING] = "forking", [SERVICE_SIMPLE] = "simple", - [SERVICE_FINISH] = "finish" + [SERVICE_FINISH] = "finish", + [SERVICE_DBUS] = "dbus" }; DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType); @@ -2137,5 +2236,8 @@ const UnitVTable service_vtable = { .cgroup_notify_empty = service_cgroup_notify_event, + .bus_name_owner_change = service_bus_name_owner_change, + .bus_query_pid_done = service_bus_query_pid_done, + .enumerate = service_enumerate };