X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Fservice.c;h=5543077657bf377b0b790399b801a409fc96079e;hb=ac155bb885f9ea8aac3979a6b2686f0c8a9cc6e3;hp=feecbbe2b6a93ad919e8bf32aec71f2069aefe25;hpb=dc1ecd78e9f046880d10ddb45cf9b06df1084b10;p=elogind.git diff --git a/src/service.c b/src/service.c index feecbbe2b..554307765 100644 --- a/src/service.c +++ b/src/service.c @@ -108,7 +108,7 @@ static void service_init(Unit *u) { Service *s = SERVICE(u); assert(u); - assert(u->meta.load_state == UNIT_STUB); + assert(u->load_state == UNIT_STUB); s->timeout_usec = DEFAULT_TIMEOUT_USEC; s->restart_usec = DEFAULT_RESTART_USEC; @@ -187,11 +187,11 @@ static void service_close_socket_fd(Service *s) { static void service_connection_unref(Service *s) { assert(s); - if (!s->accept_socket) + if (!UNIT_DEREF(s->accept_socket)) return; - socket_connection_unref(s->accept_socket); - s->accept_socket = NULL; + socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket))); + unit_ref_unset(&s->accept_socket); } static void service_done(Unit *u) { @@ -224,7 +224,7 @@ static void service_done(Unit *u) { service_unwatch_control_pid(s); if (s->bus_name) { - unit_unwatch_bus_name(UNIT(u), s->bus_name); + unit_unwatch_bus_name(u, s->bus_name); free(s->bus_name); s->bus_name = NULL; } @@ -232,7 +232,7 @@ static void service_done(Unit *u) { service_close_socket_fd(s); service_connection_unref(s); - set_free(s->configured_sockets); + unit_ref_unset(&s->accept_socket); unit_unwatch_timer(u, &s->timer_watch); } @@ -360,7 +360,7 @@ finish: } static int sysv_fix_order(Service *s) { - Meta *other; + Unit *other; int r; assert(s); @@ -496,7 +496,7 @@ static int service_load_sysv_path(Service *s, const char *path) { s->sysv_mtime = timespec_load(&st.st_mtim); if (null_or_empty(&st)) { - u->meta.load_state = UNIT_MASKED; + u->load_state = UNIT_MASKED; r = 0; goto finish; } @@ -841,7 +841,7 @@ static int service_load_sysv_path(Service *s, const char *path) { s->restart = SERVICE_RESTART_NO; if (s->meta.manager->sysv_console) - s->exec_context.std_output = EXEC_OUTPUT_SYSLOG_AND_CONSOLE; + s->exec_context.std_output = EXEC_OUTPUT_JOURNAL_AND_CONSOLE; s->exec_context.kill_mode = KILL_PROCESS; @@ -865,7 +865,7 @@ static int service_load_sysv_path(Service *s, const char *path) { goto finish; } - u->meta.description = d; + u->description = d; } /* The priority that has been set in /etc/rcN.d/ hierarchies @@ -874,7 +874,7 @@ static int service_load_sysv_path(Service *s, const char *path) { if (s->sysv_start_priority_from_rcnd >= 0) s->sysv_start_priority = s->sysv_start_priority_from_rcnd; - u->meta.load_state = UNIT_LOADED; + u->load_state = UNIT_LOADED; r = 0; finish: @@ -1008,7 +1008,7 @@ static int service_load_sysv(Service *s) { #endif static int fsck_fix_order(Service *s) { - Meta *other; + Unit *other; int r; assert(s); @@ -1138,13 +1138,13 @@ static int service_load(Unit *u) { #ifdef HAVE_SYSV_COMPAT /* Load a classic init script as a fallback, if we couldn't find anything */ - if (u->meta.load_state == UNIT_STUB) + if (u->load_state == UNIT_STUB) if ((r = service_load_sysv(s)) < 0) return r; #endif /* Still nothing found? Then let's give up */ - if (u->meta.load_state == UNIT_STUB) + if (u->load_state == UNIT_STUB) return -ENOENT; /* We were able to load something, then let's add in the @@ -1153,7 +1153,7 @@ static int service_load(Unit *u) { return r; /* This is a new unit? Then let's add in some extras */ - if (u->meta.load_state == UNIT_LOADED) { + if (u->load_state == UNIT_LOADED) { service_fix_output(s); if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) @@ -1371,86 +1371,22 @@ static int service_search_main_pid(Service *s) { return 0; } -static int service_get_sockets(Service *s, Set **_set) { - Set *set; +static void service_notify_sockets_dead(Service *s) { Iterator i; - char *t; - int r; - - assert(s); - assert(_set); - - if (s->socket_fd >= 0) - return 0; - - if (!set_isempty(s->configured_sockets)) - return 0; - - /* Collects all Socket objects that belong to this - * service. Note that a service might have multiple sockets - * via multiple names. */ - - if (!(set = set_new(NULL, NULL))) - return -ENOMEM; - - SET_FOREACH(t, s->meta.names, i) { - char *k; - Unit *p; - - /* Look for all socket objects that go by any of our - * units and collect their fds */ - - if (!(k = unit_name_change_suffix(t, ".socket"))) { - r = -ENOMEM; - goto fail; - } - - p = manager_get_unit(s->meta.manager, k); - free(k); - - if (!p) - continue; - - if ((r = set_put(set, p)) < 0) - goto fail; - } - - *_set = set; - return 0; - -fail: - set_free(set); - return r; -} - -static int service_notify_sockets_dead(Service *s) { - Iterator i; - Set *set, *free_set = NULL; - Socket *sock; - int r; + Unit *u; assert(s); /* Notifies all our sockets when we die */ if (s->socket_fd >= 0) - return 0; - - if (!set_isempty(s->configured_sockets)) - set = s->configured_sockets; - else { - if ((r = service_get_sockets(s, &free_set)) < 0) - return r; - - set = free_set; - } - - SET_FOREACH(sock, set, i) - socket_notify_service_dead(sock); + return; - set_free(free_set); + SET_FOREACH(u, s->meta.dependencies[UNIT_TRIGGERED_BY], i) + if (u->type == UNIT_SOCKET) + socket_notify_service_dead(SOCKET(u)); - return 0; + return; } static void service_unwatch_pid_file(Service *s) { @@ -1458,8 +1394,8 @@ static void service_unwatch_pid_file(Service *s) { return; log_debug("Stopping watch for %s's PID file %s", s->meta.id, s->pid_file_pathspec->path); - pathspec_unwatch(s->pid_file_pathspec, UNIT(s)); - pathspec_done(s->pid_file_pathspec); + path_spec_unwatch(s->pid_file_pathspec, UNIT(s)); + path_spec_done(s->pid_file_pathspec); free(s->pid_file_pathspec); s->pid_file_pathspec = NULL; } @@ -1622,8 +1558,7 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { int r; int *rfds = NULL; unsigned rn_fds = 0; - Set *set, *free_set = NULL; - Socket *sock; + Unit *u; assert(s); assert(fds); @@ -1632,18 +1567,15 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { if (s->socket_fd >= 0) return 0; - if (!set_isempty(s->configured_sockets)) - set = s->configured_sockets; - else { - if ((r = service_get_sockets(s, &free_set)) < 0) - return r; - - set = free_set; - } - - SET_FOREACH(sock, set, i) { + SET_FOREACH(u, s->meta.dependencies[UNIT_TRIGGERED_BY], i) { int *cfds; unsigned cn_fds; + Socket *sock; + + if (u->type != UNIT_SOCKET) + continue; + + sock = SOCKET(u); if ((r = socket_collect_fds(sock, &cfds, &cn_fds)) < 0) goto fail; @@ -1676,12 +1608,9 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { *fds = rfds; *n_fds = rn_fds; - set_free(free_set); - return 0; fail: - set_free(set); free(rfds); return r; @@ -2092,6 +2021,11 @@ static void service_enter_start(Service *s) { else service_unwatch_main_pid(s); + /* We want to ensure that nobody leaks processes from + * START_PRE here, so let's go on a killing spree, People + * should not spawn long running processes from START_PRE. */ + cgroup_bonding_kill_list(s->meta.cgroup_bondings, SIGKILL, true, NULL); + if (s->type == SERVICE_FORKING) { s->control_command_id = SERVICE_EXEC_START; c = s->control_command = s->exec_command[SERVICE_EXEC_START]; @@ -2161,6 +2095,11 @@ static void service_enter_start_pre(Service *s) { service_unwatch_control_pid(s); if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) { + + /* Before we start anything, let's clear up what might + * be left from previous runs. */ + cgroup_bonding_kill_list(s->meta.cgroup_bondings, SIGKILL, true, NULL); + s->control_command_id = SERVICE_EXEC_START_PRE; if ((r = service_spawn(s, @@ -2352,7 +2291,7 @@ static int service_start(Unit *u) { /* Make sure we don't enter a busy loop of some kind. */ if (!ratelimit_test(&s->ratelimit)) { - log_warning("%s start request repeated too quickly, refusing to start.", u->meta.id); + log_warning("%s start request repeated too quickly, refusing to start.", u->id); return -ECANCELED; } @@ -2637,7 +2576,7 @@ static int service_watch_pid_file(Service *s) { int r; log_debug("Setting watch for %s's PID file %s", s->meta.id, s->pid_file_pathspec->path); - r = pathspec_watch(s->pid_file_pathspec, UNIT(s)); + r = path_spec_watch(s->pid_file_pathspec, UNIT(s)); if (r < 0) goto fail; @@ -2687,11 +2626,11 @@ static void service_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { assert(fd >= 0); assert(s->state == SERVICE_START || s->state == SERVICE_START_POST); assert(s->pid_file_pathspec); - assert(pathspec_owns_inotify_fd(s->pid_file_pathspec, fd)); + assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd)); - log_debug("inotify event for %s", u->meta.id); + log_debug("inotify event for %s", u->id); - if (pathspec_fd_event(s->pid_file_pathspec, events) < 0) + if (path_spec_fd_event(s->pid_file_pathspec, events) < 0) goto fail; if (service_retry_pid_file(s) == 0) @@ -2740,7 +2679,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { } log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status); + "%s: main process exited, code=%s, status=%i", u->id, sigchld_code_to_string(code), status); s->failure = s->failure || !success; if (s->main_command && @@ -2750,7 +2689,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { /* There is another command to * * execute, so let's do that. */ - log_debug("%s running next main command for state %s", u->meta.id, service_state_to_string(s->state)); + log_debug("%s running next main command for state %s", u->id, service_state_to_string(s->state)); service_run_next_main(s, success); } else { @@ -2812,7 +2751,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { } log_full(success ? LOG_DEBUG : LOG_NOTICE, - "%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status); + "%s: control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status); s->failure = s->failure || !success; if (s->control_command && @@ -2822,7 +2761,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { /* There is another command to * * execute, so let's do that. */ - log_debug("%s running next control command for state %s", u->meta.id, service_state_to_string(s->state)); + log_debug("%s running next control command for state %s", u->id, service_state_to_string(s->state)); service_run_next_control(s, success); } else { @@ -2832,7 +2771,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { s->control_command = NULL; s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; - log_debug("%s got final SIGCHLD for state %s", u->meta.id, service_state_to_string(s->state)); + log_debug("%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state)); switch (s->state) { @@ -2941,32 +2880,32 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { case SERVICE_START_PRE: case SERVICE_START: - log_warning("%s operation timed out. Terminating.", u->meta.id); + log_warning("%s operation timed out. Terminating.", u->id); service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); break; case SERVICE_START_POST: - log_warning("%s operation timed out. Stopping.", u->meta.id); + log_warning("%s operation timed out. Stopping.", u->id); service_enter_stop(s, false); break; case SERVICE_RELOAD: - log_warning("%s operation timed out. Stopping.", u->meta.id); + log_warning("%s operation timed out. Stopping.", u->id); s->reload_failure = true; service_enter_running(s, true); break; case SERVICE_STOP: - log_warning("%s stopping timed out. Terminating.", u->meta.id); + log_warning("%s stopping timed out. Terminating.", u->id); service_enter_signal(s, SERVICE_STOP_SIGTERM, false); break; case SERVICE_STOP_SIGTERM: if (s->exec_context.send_sigkill) { - log_warning("%s stopping timed out. Killing.", u->meta.id); + log_warning("%s stopping timed out. Killing.", u->id); service_enter_signal(s, SERVICE_STOP_SIGKILL, false); } else { - log_warning("%s stopping timed out. Skipping SIGKILL.", u->meta.id); + log_warning("%s stopping timed out. Skipping SIGKILL.", u->id); service_enter_stop_post(s, false); } @@ -2977,33 +2916,33 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) { * Must be something we cannot kill, so let's just be * weirded out and continue */ - log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id); + log_warning("%s still around after SIGKILL. Ignoring.", u->id); service_enter_stop_post(s, false); break; case SERVICE_STOP_POST: - log_warning("%s stopping timed out (2). Terminating.", u->meta.id); + log_warning("%s stopping timed out (2). Terminating.", u->id); service_enter_signal(s, SERVICE_FINAL_SIGTERM, false); break; case SERVICE_FINAL_SIGTERM: if (s->exec_context.send_sigkill) { - log_warning("%s stopping timed out (2). Killing.", u->meta.id); + log_warning("%s stopping timed out (2). Killing.", u->id); service_enter_signal(s, SERVICE_FINAL_SIGKILL, false); } else { - log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->meta.id); + log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->id); service_enter_dead(s, false, true); } break; case SERVICE_FINAL_SIGKILL: - log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->meta.id); + log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id); service_enter_dead(s, false, true); break; case SERVICE_AUTO_RESTART: - log_info("%s holdoff time over, scheduling restart.", u->meta.id); + log_info("%s holdoff time over, scheduling restart.", u->id); service_enter_restart(s); break; @@ -3017,7 +2956,7 @@ static void service_cgroup_notify_event(Unit *u) { assert(u); - log_debug("%s: cgroup is empty", u->meta.id); + log_debug("%s: cgroup is empty", u->id); switch (s->state) { @@ -3073,17 +3012,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { if (s->notify_access == NOTIFY_NONE) { log_warning("%s: Got notification message from PID %lu, but reception is disabled.", - u->meta.id, (unsigned long) pid); + u->id, (unsigned long) pid); return; } if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) { log_warning("%s: Got notification message from PID %lu, but reception only permitted for PID %lu", - u->meta.id, (unsigned long) pid, (unsigned long) s->main_pid); + u->id, (unsigned long) pid, (unsigned long) s->main_pid); return; } - log_debug("%s: Got message", u->meta.id); + log_debug("%s: Got message", u->id); /* Interpret MAINPID= */ if ((e = strv_find_prefix(tags, "MAINPID=")) && @@ -3095,7 +3034,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { if (parse_pid(e + 8, &pid) < 0) log_warning("Failed to parse notification message %s", e); else { - log_debug("%s: got %s", u->meta.id, e); + log_debug("%s: got %s", u->id, e); service_set_main_pid(s, pid); } } @@ -3104,7 +3043,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START && strv_find(tags, "READY=1")) { - log_debug("%s: got READY=1", u->meta.id); + log_debug("%s: got READY=1", u->id); service_enter_start_post(s); } @@ -3119,7 +3058,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) { return; } - log_debug("%s: got %s", u->meta.id, e); + log_debug("%s: got %s", u->id, e); free(s->status_text); s->status_text = t; @@ -3170,7 +3109,7 @@ static void sysv_facility_in_insserv_conf(Manager *mgr) { Unit *u; if (sysv_translate_facility(parsed[0], NULL, &facility) < 0) continue; - if ((u = manager_get_unit(mgr, facility)) && (u->meta.type == UNIT_TARGET)) { + if ((u = manager_get_unit(mgr, facility)) && (u->type == UNIT_TARGET)) { UnitDependency e; char *dep = NULL, *name, **j; @@ -3323,7 +3262,7 @@ static int service_enumerate(Manager *m) { SET_FOREACH(service, runlevel_services[i], j) { service = unit_follow_merge(service); - if (service->meta.fragment_path) + if (service->fragment_path) continue; if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0) @@ -3340,7 +3279,7 @@ static int service_enumerate(Manager *m) { SET_FOREACH(service, shutdown_services, j) { service = unit_follow_merge(service); - if (service->meta.fragment_path) + if (service->fragment_path) continue; if ((r = unit_add_two_dependencies_by_name(service, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0) @@ -3384,11 +3323,11 @@ static void service_bus_name_owner_change( 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); + log_debug("%s's D-Bus name %s changed owner from %s to %s", u->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); + log_debug("%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner); else - log_debug("%s's D-Bus name %s now registered by %s", u->meta.id, name, new_owner); + log_debug("%s's D-Bus name %s now registered by %s", u->id, name, new_owner); s->bus_name_good = !!new_owner; @@ -3411,7 +3350,7 @@ static void service_bus_name_owner_change( /* Try to acquire PID from bus service */ log_debug("Trying to acquire PID from D-Bus name..."); - bus_query_pid(u->meta.manager, name); + bus_query_pid(u->manager, name); } } @@ -3425,7 +3364,7 @@ static void service_bus_query_pid_done( assert(s); assert(name); - log_debug("%s's D-Bus name %s is now owned by process %u", u->meta.id, name, (unsigned) pid); + log_debug("%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid); if (s->main_pid <= 0 && (s->state == SERVICE_START || @@ -3436,6 +3375,7 @@ static void service_bus_query_pid_done( } int service_set_socket_fd(Service *s, int fd, Socket *sock) { + assert(s); assert(fd >= 0); @@ -3454,9 +3394,10 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock) { s->socket_fd = fd; s->got_socket_fd = true; - s->accept_socket = sock; - return 0; + unit_ref_set(&s->accept_socket, UNIT(sock)); + + return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); } static void service_reset_failed(Unit *u) { @@ -3612,6 +3553,7 @@ DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); const UnitVTable service_vtable = { .suffix = ".service", + .object_size = sizeof(Service), .sections = "Unit\0" "Service\0"