X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Funit.c;h=c546035ca1c83e3280d091b615f6fdfd897eb521;hp=374d2e133106def502cca34b9e24f364af1d9cdd;hb=a3d4e06dfa234bf2a9398c8e534b705b68aa50a1;hpb=b86d44e5abc05dd13ad89cf1a4a69f32203f73e6 diff --git a/src/unit.c b/src/unit.c index 374d2e133..c546035ca 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, @@ -48,7 +49,8 @@ const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_MOUNT] = &mount_vtable, [UNIT_AUTOMOUNT] = &automount_vtable, [UNIT_SNAPSHOT] = &snapshot_vtable, - [UNIT_SWAP] = &swap_vtable + [UNIT_SWAP] = &swap_vtable, + [UNIT_PATH] = &path_vtable }; Unit *unit_new(Manager *m) { @@ -66,6 +68,7 @@ Unit *unit_new(Manager *m) { u->meta.manager = m; u->meta.type = _UNIT_TYPE_INVALID; + u->meta.deserialized_job = _JOB_TYPE_INVALID; return u; } @@ -317,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); @@ -338,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); @@ -402,10 +401,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; @@ -534,7 +530,10 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { assert(u); assert(c); - if (c->std_output != EXEC_OUTPUT_KERNEL && c->std_output != EXEC_OUTPUT_SYSLOG) + if (c->std_output != EXEC_OUTPUT_KMSG && + c->std_output != EXEC_OUTPUT_SYSLOG && + c->std_error != EXEC_OUTPUT_KMSG && + c->std_error != EXEC_OUTPUT_SYSLOG) return 0; /* If syslog or kernel logging is requested, make sure our own @@ -543,7 +542,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; @@ -590,17 +589,19 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tActive Enter Timestamp: %s\n" "%s\tActive Exit Timestamp: %s\n" "%s\tInactive Enter Timestamp: %s\n" - "%s\tGC Check Good: %s\n", + "%s\tGC Check Good: %s\n" + "%s\tOnly By Dependency: %s\n", prefix, u->meta.id, prefix, unit_description(u), prefix, strna(u->meta.instance), prefix, unit_load_state_to_string(u->meta.load_state), prefix, unit_active_state_to_string(unit_active_state(u)), - prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.inactive_exit_timestamp)), - prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp)), - prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp)), - prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp)), - prefix, yes_no(unit_check_gc(u))); + prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.inactive_exit_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_enter_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->meta.active_exit_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->meta.inactive_enter_timestamp.realtime)), + prefix, yes_no(unit_check_gc(u)), + prefix, yes_no(u->meta.only_by_dependency)); SET_FOREACH(t, u->meta.names, i) fprintf(f, "%s\tName: %s\n", prefix, t); @@ -735,9 +736,10 @@ fail: } /* Errors: - * -EBADR: This unit type does not support starting. - * -EALREADY: Unit is already started. - * -EAGAIN: An operation is already in progress. Retry later. + * -EBADR: This unit type does not support starting. + * -EALREADY: Unit is already started. + * -EAGAIN: An operation is already in progress. Retry later. + * -ECANCELED: Too many requests for now. */ int unit_start(Unit *u) { UnitActiveState state; @@ -924,7 +926,7 @@ static void retroactively_stop_dependencies(Unit *u) { void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { bool unexpected = false; - usec_t ts; + timestamp ts; assert(u); assert(os < _UNIT_ACTIVE_STATE_MAX); @@ -937,7 +939,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { * this function will be called too and the utmp code below * relies on that! */ - ts = now(CLOCK_REALTIME); + timestamp_get(&ts); if (os == UNIT_INACTIVE && ns != UNIT_INACTIVE) u->meta.inactive_exit_timestamp = ts; @@ -949,6 +951,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns)) u->meta.active_exit_timestamp = ts; + timer_unit_notify(u, ns); + path_unit_notify(u, ns); + if (u->meta.job) { if (u->meta.job->state == JOB_WAITING) @@ -958,56 +963,54 @@ 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) { 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 (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"); } } @@ -1027,8 +1030,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)) @@ -1784,6 +1786,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds) { if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0) return r; + if (u->meta.job) + unit_serialize_item(u, f, "job", job_type_to_string(u->meta.job->type)); + /* End marker */ fputc('\n', f); return 0; @@ -1850,6 +1855,17 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { } else v = l+k; + if (streq(l, "job")) { + JobType type; + + if ((type = job_type_from_string(v)) < 0) + log_debug("Failed to parse job type value %s", v); + else + u->meta.deserialized_job = type; + + continue; + } + if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0) return r; } @@ -1892,6 +1908,25 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { return 0; } +int unit_coldplug(Unit *u) { + int r; + + assert(u); + + if (UNIT_VTABLE(u)->coldplug) + if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0) + return r; + + if (u->meta.deserialized_job >= 0) { + if ((r = manager_add_job(u->meta.manager, u->meta.deserialized_job, u, JOB_FAIL, false, NULL)) < 0) + return r; + + u->meta.deserialized_job = _JOB_TYPE_INVALID; + } + + return 0; +} + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = "service", [UNIT_TIMER] = "timer",