job.c revision 28c758de94bc8ba97b89d9dab3f517cf466978d0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2010 Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* used for deserialization */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* We don't link it here, that's what job_dependency() is for */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(run_queue, j->manager->run_queue, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(j->timer_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Detach from next 'bigger' objects */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* daemon-reload should be transparent to job observers */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool job_type_allows_late_merge(JobType t) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Tells whether it is OK to merge a job of type 't' with an already
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * running job.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Reloads cannot be merged this way. Think of the sequence:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * 1. Reload of a daemon is in progress; the daemon has already loaded
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * its config file, but hasn't completed the reload operation yet.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * 2. Edit foo's config file.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * 3. Trigger another reload to have the daemon use the new config.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Should the second reload job be merged into the first one, the daemon
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * would not know about the new config.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * JOB_RESTART jobs on the other hand can be merged, because they get
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * patched into JOB_START after stopping the unit. So if we see a
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * JOB_RESTART running, it means the unit hasn't stopped yet and at
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * this time the merge is still allowed. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_merge_into_installed(Job *j, Job *other) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_type_merge_and_collapse(&j->type, other->type, j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->override = j->override || other->override;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->irreversible = j->irreversible || other->irreversible;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->ignore_order = j->ignore_order || other->ignore_order;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_finish_and_invalidate(uj, JOB_CANCELED, false);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* not conflicting, i.e. mergeable */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->type == JOB_NOP || uj->state == JOB_WAITING ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Merged into installed job %s/%s as %u",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* already running and not safe to merge into */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Patch uj to become a merged job and re-run it. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* XXX It should be safer to queue j to run after uj finishes, but it is
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * not currently possible to have more than one installed job per unit. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Merged into running job, re-running: %s/%s as %u",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Install the job */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Installed new job %s/%s as %u",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Unit %s already has a job installed. Not installing deserialized job.",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Reinstalled deserialized job %s/%s as %u",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringJobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Adds a new job link, which encodes that the 'subject' job
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * needs the 'object' job in some way. If 'subject' is NULL
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * this means the 'anchor' job (i.e. the one the user
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * explicitly asked for) is the requester. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_PREPEND(subject, subject->subject_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_PREPEND(object, object->object_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid job_dependency_free(JobDependency *l) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(subject, l->subject->subject_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(object, l->object->object_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid job_dump(Job *j, FILE*f, const char *prefix) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "%s-> Job %u:\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "%s\tAction: %s -> %s\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "%s\tState: %s\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "%s\tForced: %s\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "%s\tIrreversible: %s\n",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering prefix, j->unit->id, job_type_to_string(j->type),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Merging is commutative, so imagine the matrix as symmetric. We store only
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * its lower triangle to avoid duplication. We don't store the main diagonal,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * because A merged with A is simply A.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * If the resulting type is collapsed immediately afterwards (to get rid of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * the following properties hold:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Merging is associative! A merged with B merged with C is the same as
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * A merged with C merged with B.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Mergeability is transitive! If A can be merged with B and B with C then
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * A also with C.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Also, if A merged with B cannot be merged with C, then either A or B cannot
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * be merged with C either.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic const JobType job_merging_table[] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*********************************************************************************/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringJobType job_type_lookup_merge(JobType a, JobType b) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return job_merging_table[(a - 1) * a / 2 + b];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringbool job_type_is_redundant(JobType a, UnitActiveState b) {
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletarvoid job_type_collapse(JobType *t, Unit *u) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JobType t = job_type_lookup_merge(*a, b);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Checks whether there is any job running for the units this
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * job needs to be running after (in the case of a 'positive'
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * job type) or before (in the case of a 'negative' job
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Note that unit types have a say in what is runnable,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * too. For example, if they return -EAGAIN from
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * unit_start() they can indicate they are not
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * runnable yet. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* First check if there is an override */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Immediate result is that the job is or might be
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * started. In this case lets wait for the
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * dependencies, regardless whether they are
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * starting or stopping something. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Also, if something else is being stopped and we should
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * change state after it, then lets wait. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* This means that for a service a and a service b where b
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * shall be started after a:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * start a + start b → 1st step start a, 2nd step start b
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * start a + stop b → 1st step stop b, 2nd step start a
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * stop a + start b → 1st step stop a, 2nd step start b
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * stop a + stop b → 1st step stop b, 2nd step stop a
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * This has the side effect that restarts are properly
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * synchronized too. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_change_type(Job *j, JobType newtype) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Converting job %s/%s -> %s/%s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit->id, job_type_to_string(j->type),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit->id, job_type_to_string(newtype));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(run_queue, j->manager->run_queue, j);
7ca7021a9e0c443d40d0af5e9a7e1962d8032229Michal Sekletar /* While we execute this operation the job might go away (for
7ca7021a9e0c443d40d0af5e9a7e1962d8032229Michal Sekletar * example: because it is replaced by a new, conflicting
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * job.) To make sure we don't access a freed job later on we
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * store the id here, so that we can verify the job is still
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If this unit cannot be started, then simply wait */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering UnitActiveState t = unit_active_state(j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If this unit cannot stopped, then simply wait. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = job_finish_and_invalidate(j, JOB_DONE, true);
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt else if (r == -EBADR)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (r == -ENOEXEC)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = job_finish_and_invalidate(j, JOB_INVALID, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (r == -EAGAIN) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = job_finish_and_invalidate(j, JOB_FAILED, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const UnitStatusMessageFormats *format_table;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_table = &UNIT_VTABLE(u)->status_message_formats;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return format_table->finished_start_job[result];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (t == JOB_STOP || t == JOB_RESTART)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return format_table->finished_stop_job[result];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Return generic strings */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Started %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Failed to start %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Dependency failed for %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Timed out starting %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_STOP || t == JOB_RESTART) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Stopped %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Stopped (with error) %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Timed out stoppping %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_RELOAD) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Reloaded %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Reload failed for %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Timed out reloading %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic ignored "-Wformat-nonliteral"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_print_status_message(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_flip_auto_status(u->manager, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_status_printf(u->manager, false, NULL, "See 'systemctl status %s' for details.", u->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_flip_auto_status(u->manager, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_flip_auto_status(u->manager, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_STOP || t == JOB_RESTART) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_flip_auto_status(u->manager, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_VERIFY_ACTIVE) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* When verify-active detects the unit is inactive, report it.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * Most likely a DEPEND warning from a requisiting unit will
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * occur next and it's nice to see what was requisited. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic ignored "-Wformat-nonliteral"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_log_status_message(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Skip this if it goes to the console. since we already print
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * to the console anyway... */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format_try_harder(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(buf, sizeof(buf), format, unit_description(u));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "RESULT=%s", job_result_to_string(result),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_STOP)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "RESULT=%s", job_result_to_string(result),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "RESULT=%s", job_result_to_string(result),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(u->id, "Job %s/%s finished, result=%s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->id, job_type_to_string(t), job_result_to_string(result));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Patch restart jobs so that they become normal start jobs */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_DONE && t == JOB_RESTART) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_FAILED || result == JOB_INVALID)
if (t == JOB_START ||
t == JOB_VERIFY_ACTIVE) {
} else if (t == JOB_STOP) {
u->id,
u->id,
NULL);
assert(j);
r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source);
assert(j);
if (j->in_run_queue)
j->in_run_queue = true;
assert(j);
if (j->in_dbus_queue)
* connection/client. */
j->in_dbus_queue = true;
assert(j);
return NULL;
if (j->begin_usec > 0)
assert(j);
size_t k;
if (feof(f))
return -errno;
JobType t;
t = job_type_from_string(v);
else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
j->type = t;
JobState s;
s = job_state_from_string(v);
j->state = s;
b = parse_boolean(v);
b = parse_boolean(v);
b = parse_boolean(v);
b = parse_boolean(v);
unsigned long long ull;
assert(j);
if (j->begin_usec <= 0)
if (j->timer_event_source)
r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source);
assert(j);
assert(u);
if (j->timer_event_source) {