X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=unit.c;h=6406015b4bc075cf9855ff222f4fe0bfa9c19533;hp=e6331b44d3961587734676bf042de17b2fea7ff8;hb=8e471ccd1583371cab19a6263b8952b37d069b07;hpb=50159e6a776143be076f8ebe73a8a59447050698 diff --git a/unit.c b/unit.c index e6331b44d..6406015b4 100644 --- a/unit.c +++ b/unit.c @@ -219,6 +219,7 @@ int unit_set_description(Unit *u, const char *description) { void unit_add_to_load_queue(Unit *u) { assert(u); + assert(u->meta.type != _UNIT_TYPE_INVALID); if (u->meta.load_state != UNIT_STUB || u->meta.in_load_queue) return; @@ -239,6 +240,7 @@ void unit_add_to_cleanup_queue(Unit *u) { void unit_add_to_dbus_queue(Unit *u) { assert(u); + assert(u->meta.type != _UNIT_TYPE_INVALID); if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue || set_isempty(u->meta.manager->subscribed)) return; @@ -394,6 +396,8 @@ int unit_merge(Unit *u, Unit *other) { assert(other); assert(u->meta.manager == other->meta.manager); + other = unit_follow_merge(other); + if (other == u) return 0; @@ -403,7 +407,14 @@ int unit_merge(Unit *u, Unit *other) { if (u->meta.type != u->meta.type) return -EINVAL; - if (other->meta.load_state != UNIT_STUB) + if (other->meta.load_state != UNIT_STUB && + other->meta.load_state != UNIT_FAILED) + return -EEXIST; + + if (other->meta.job) + return -EEXIST; + + if (unit_active_state(other) != UNIT_INACTIVE) return -EEXIST; /* Merge names */ @@ -413,11 +424,16 @@ int unit_merge(Unit *u, Unit *other) { for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) merge_dependencies(u, other, d); - unit_add_to_dbus_queue(u); - other->meta.load_state = UNIT_MERGED; other->meta.merged_into = u; + /* If there is still some data attached to the other node, we + * don't need it anymore, and can free it. */ + if (other->meta.load_state != UNIT_STUB) + if (UNIT_VTABLE(other)->done) + UNIT_VTABLE(other)->done(other); + + unit_add_to_dbus_queue(u); unit_add_to_cleanup_queue(other); return 0; @@ -491,6 +507,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { char *p2; const char *prefix2; CGroupBonding *b; + char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX]; assert(u); @@ -503,11 +520,15 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s→ Unit %s:\n" "%s\tDescription: %s\n" "%s\tUnit Load State: %s\n" - "%s\tUnit Active State: %s\n", + "%s\tUnit Active State: %s\n" + "%s\tActive Enter Timestamp: %s\n" + "%s\tActive Exit Timestamp: %s\n", prefix, unit_id(u), prefix, unit_description(u), prefix, unit_load_state_to_string(u->meta.load_state), - prefix, unit_active_state_to_string(unit_active_state(u))); + prefix, unit_active_state_to_string(unit_active_state(u)), + prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.active_enter_timestamp)), + prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_exit_timestamp))); SET_FOREACH(t, u->meta.names, i) fprintf(f, "%s\tName: %s\n", prefix, t); @@ -518,27 +539,28 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { Unit *other; - if (set_isempty(u->meta.dependencies[d])) - continue; - SET_FOREACH(other, u->meta.dependencies[d], i) fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), unit_id(other)); } - fprintf(f, - "%s\tRecursive Stop: %s\n" - "%s\tStop When Unneeded: %s\n", - prefix, yes_no(u->meta.recursive_stop), - prefix, yes_no(u->meta.stop_when_unneeded)); - if (u->meta.load_state == UNIT_LOADED) { + fprintf(f, + "%s\tRecursive Stop: %s\n" + "%s\tStop When Unneeded: %s\n", + prefix, yes_no(u->meta.recursive_stop), + prefix, yes_no(u->meta.stop_when_unneeded)); + LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings) fprintf(f, "%s\tControlGroup: %s:%s\n", prefix, b->controller, b->path); if (UNIT_VTABLE(u)->dump) UNIT_VTABLE(u)->dump(u, f, prefix2); - } + + } else if (u->meta.load_state == UNIT_MERGED) + fprintf(f, + "%s\tMerged into: %s\n", + prefix, unit_id(u->meta.merged_into)); if (u->meta.job) job_dump(u->meta.job, f, prefix2); @@ -826,14 +848,20 @@ static void retroactively_stop_dependencies(Unit *u) { } void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { + bool unexpected = false; + assert(u); assert(os < _UNIT_ACTIVE_STATE_MAX); assert(ns < _UNIT_ACTIVE_STATE_MAX); assert(!(os == UNIT_ACTIVE && ns == UNIT_ACTIVATING)); assert(!(os == UNIT_INACTIVE && ns == UNIT_DEACTIVATING)); - if (os == ns) - return; + /* Note that this is called for all low-level state changes, + * even if they might map to the same high-level + * UnitActiveState! That means that ns == os is OK an expected + * behaviour here. For example: if a mount point is remounted + * this function will be called too and the utmp code below + * relies on that! */ if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns)) u->meta.active_enter_timestamp = now(CLOCK_REALTIME); @@ -862,26 +890,24 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { case JOB_START: case JOB_VERIFY_ACTIVE: - if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) { + if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) job_finish_and_invalidate(u->meta.job, true); - return; - } else if (ns == UNIT_ACTIVATING) - return; - else + else if (ns != UNIT_ACTIVATING) { + unexpected = true; job_finish_and_invalidate(u->meta.job, false); + } break; case JOB_RELOAD: case JOB_RELOAD_OR_START: - if (ns == UNIT_ACTIVE) { + if (ns == UNIT_ACTIVE) job_finish_and_invalidate(u->meta.job, true); - return; - } else if (ns == UNIT_ACTIVATING || ns == UNIT_ACTIVE_RELOADING) - return; - else + else if (ns != UNIT_ACTIVATING && ns != UNIT_ACTIVE_RELOADING) { + unexpected = true; job_finish_and_invalidate(u->meta.job, false); + } break; @@ -889,13 +915,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { case JOB_RESTART: case JOB_TRY_RESTART: - if (ns == UNIT_INACTIVE) { + if (ns == UNIT_INACTIVE) job_finish_and_invalidate(u->meta.job, true); - return; - } else if (ns == UNIT_DEACTIVATING) - return; - else + else if (ns != UNIT_DEACTIVATING) { + unexpected = true; job_finish_and_invalidate(u->meta.job, false); + } break; @@ -908,22 +933,27 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { /* If this state change happened without being requested by a * job, then let's retroactively start or stop dependencies */ - if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) - retroactively_start_dependencies(u); - else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) - retroactively_stop_dependencies(u); + if (unexpected) { + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) + retroactively_start_dependencies(u); + else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) + retroactively_stop_dependencies(u); + } if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns)) { if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) { + log_info("D-Bus became available, trying to reconnect."); /* The bus just got started, hence try to connect to it. */ bus_init_system(u->meta.manager); bus_init_api(u->meta.manager); } - if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE)) + if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE)) { /* The syslog daemon just got started, hence try to connect to it. */ + log_info("Syslog became available, trying to reconnect."); log_open_syslog(); + } } else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns)) {