X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Funit.c;h=9fed5a0f4e81087ea17dc5c98f4af5163f19f0cb;hb=dd1eb43ba771d4d56b20b4c93ba3acc59475f642;hp=bb2b8c2fe010cb917b2f1df95b622528b332cf81;hpb=cca098b09535f58c638ed41310be60504be49bc4;p=elogind.git diff --git a/src/unit.c b/src/unit.c index bb2b8c2fe..9fed5a0f4 100644 --- a/src/unit.c +++ b/src/unit.c @@ -38,6 +38,7 @@ #include "unit-name.h" #include "specifier.h" #include "dbus-unit.h" +#include "special.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -319,10 +320,19 @@ void unit_free(Unit *u) { bus_unit_send_removed_signal(u); - /* Detach from next 'bigger' objects */ + if (u->meta.load_state != UNIT_STUB) + if (UNIT_VTABLE(u)->done) + UNIT_VTABLE(u)->done(u); + SET_FOREACH(t, u->meta.names, i) hashmap_remove_value(u->meta.manager->units, t, u); + if (u->meta.job) + job_free(u->meta.job); + + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) + bidi_set_free(u, u->meta.dependencies[d]); + if (u->meta.type != _UNIT_TYPE_INVALID) LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta); @@ -340,25 +350,12 @@ void unit_free(Unit *u) { u->meta.manager->n_in_gc_queue--; } - /* Free data and next 'smaller' objects */ - if (u->meta.job) - job_free(u->meta.job); - - if (u->meta.load_state != UNIT_STUB) - if (UNIT_VTABLE(u)->done) - UNIT_VTABLE(u)->done(u); - cgroup_bonding_free_list(u->meta.cgroup_bondings); - for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) - bidi_set_free(u, u->meta.dependencies[d]); - free(u->meta.description); free(u->meta.fragment_path); - while ((t = set_steal_first(u->meta.names))) - free(t); - set_free(u->meta.names); + set_free_free(u->meta.names); free(u->meta.instance); @@ -368,8 +365,12 @@ void unit_free(Unit *u) { UnitActiveState unit_active_state(Unit *u) { assert(u); - if (u->meta.load_state != UNIT_LOADED) - return UNIT_INACTIVE; + if (u->meta.load_state == UNIT_MERGED) + return unit_active_state(unit_follow_merge(u)); + + /* After a reload it might happen that a unit is not correctly + * loaded but still has a process around. That's why we won't + * shortcut failed loading to UNIT_INACTIVE_MAINTENANCE. */ return UNIT_VTABLE(u)->active_state(u); } @@ -404,10 +405,7 @@ static void merge_names(Unit *u, Unit *other) { complete_move(&u->meta.names, &other->meta.names); - while ((t = set_steal_first(other->meta.names))) - free(t); - - set_free(other->meta.names); + set_free_free(other->meta.names); other->meta.names = NULL; other->meta.id = NULL; @@ -469,7 +467,7 @@ int unit_merge(Unit *u, Unit *other) { if (other->meta.job) return -EEXIST; - if (unit_active_state(other) != UNIT_INACTIVE) + if (!UNIT_IS_INACTIVE_OR_MAINTENANCE(unit_active_state(other))) return -EEXIST; /* Merge names */ @@ -548,7 +546,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) return r; - if (u->meta.manager->running_as != MANAGER_SESSION) + if (u->meta.manager->running_as == MANAGER_SYSTEM) if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) return r; @@ -752,6 +750,9 @@ int unit_start(Unit *u) { assert(u); + if (u->meta.load_state != UNIT_LOADED) + return -EINVAL; + /* If this is already (being) started, then this will * succeed. Note that this will even succeed if this unit is * not startable by the user. This is relied on to detect when @@ -791,7 +792,7 @@ int unit_stop(Unit *u) { assert(u); state = unit_active_state(u); - if (state == UNIT_INACTIVE) + if (UNIT_IS_INACTIVE_OR_MAINTENANCE(state)) return -EALREADY; if (!UNIT_VTABLE(u)->stop) @@ -811,11 +812,14 @@ int unit_reload(Unit *u) { assert(u); + if (u->meta.load_state != UNIT_LOADED) + return -EINVAL; + if (!unit_can_reload(u)) return -EBADR; state = unit_active_state(u); - if (unit_active_state(u) == UNIT_ACTIVE_RELOADING) + if (unit_active_state(u) == UNIT_RELOADING) return -EALREADY; if (unit_active_state(u) != UNIT_ACTIVE) @@ -932,7 +936,7 @@ static void retroactively_stop_dependencies(Unit *u) { void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { bool unexpected = false; - timestamp ts; + dual_timestamp ts; assert(u); assert(os < _UNIT_ACTIVE_STATE_MAX); @@ -945,11 +949,11 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { * this function will be called too and the utmp code below * relies on that! */ - timestamp_get(&ts); + dual_timestamp_get(&ts); - if (os == UNIT_INACTIVE && ns != UNIT_INACTIVE) + if (UNIT_IS_INACTIVE_OR_MAINTENANCE(os) && !UNIT_IS_INACTIVE_OR_MAINTENANCE(ns)) u->meta.inactive_exit_timestamp = ts; - else if (os != UNIT_INACTIVE && ns == UNIT_INACTIVE) + else if (!UNIT_IS_INACTIVE_OR_MAINTENANCE(os) && UNIT_IS_INACTIVE_OR_MAINTENANCE(ns)) u->meta.inactive_enter_timestamp = ts; if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns)) @@ -969,56 +973,56 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { * failed previously due to EAGAIN. */ job_add_to_run_queue(u->meta.job); - else { - assert(u->meta.job->state == JOB_RUNNING); - /* Let's check whether this state change - * constitutes a finished job, or maybe - * cotradicts a running job and hence needs to - * invalidate jobs. */ + /* Let's check whether this state change constitutes a + * finished job, or maybe cotradicts a running job and + * hence needs to invalidate jobs. */ - switch (u->meta.job->type) { + switch (u->meta.job->type) { - case JOB_START: - case JOB_VERIFY_ACTIVE: + case JOB_START: + case JOB_VERIFY_ACTIVE: - if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) - job_finish_and_invalidate(u->meta.job, true); - else if (ns != UNIT_ACTIVATING) { - unexpected = true; - job_finish_and_invalidate(u->meta.job, false); - } + if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) + job_finish_and_invalidate(u->meta.job, true); + else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { + unexpected = true; + job_finish_and_invalidate(u->meta.job, false); + } - break; + break; - case JOB_RELOAD: - case JOB_RELOAD_OR_START: + case JOB_RELOAD: + case JOB_RELOAD_OR_START: + if (u->meta.job->state == JOB_RUNNING) { if (ns == UNIT_ACTIVE) job_finish_and_invalidate(u->meta.job, true); - else if (ns != UNIT_ACTIVATING && ns != UNIT_ACTIVE_RELOADING) { + else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { unexpected = true; job_finish_and_invalidate(u->meta.job, false); } + } - break; + break; - case JOB_STOP: - case JOB_RESTART: - case JOB_TRY_RESTART: + case JOB_STOP: + case JOB_RESTART: + case JOB_TRY_RESTART: - if (ns == UNIT_INACTIVE) - job_finish_and_invalidate(u->meta.job, true); - else if (ns != UNIT_DEACTIVATING) { - unexpected = true; - job_finish_and_invalidate(u->meta.job, false); - } + if (ns == UNIT_INACTIVE) + job_finish_and_invalidate(u->meta.job, true); + else if (ns == UNIT_MAINTENANCE) + job_finish_and_invalidate(u->meta.job, false); + else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { + unexpected = true; + job_finish_and_invalidate(u->meta.job, false); + } - break; + break; - default: - assert_not_reached("Job type unknown"); - } + default: + assert_not_reached("Job type unknown"); } } @@ -1038,8 +1042,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { /* The bus just might have become available, * hence try to connect to it, if we aren't * yet connected. */ - bus_init_system(u->meta.manager); - bus_init_api(u->meta.manager); + bus_init(u->meta.manager); } if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE)) @@ -1961,7 +1964,9 @@ DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", [UNIT_INACTIVE] = "inactive", + [UNIT_MAINTENANCE] = "maintenance", [UNIT_ACTIVATING] = "activating", [UNIT_DEACTIVATING] = "deactivating" };