job.c revision 28c758de94bc8ba97b89d9dab3f517cf466978d0
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/***
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2010 Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart 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
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
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***/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <assert.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <errno.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/timerfd.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/epoll.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "sd-id128.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "sd-messages.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "set.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "unit.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "macro.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "strv.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "load-fragment.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "load-dropin.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "log.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "dbus-job.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "special.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "async.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "virt.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "dbus-client-track.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringJob* job_new_raw(Unit *unit) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Job *j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* used for deserialization */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j = new0(Job, 1);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!j)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->manager = unit->manager;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit = unit;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->type = _JOB_TYPE_INVALID;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringJob* job_new(Unit *unit, JobType type) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Job *j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(type < _JOB_TYPE_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j = job_new_raw(unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!j)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->id = j->manager->current_job_id++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->type = type;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* We don't link it here, that's what job_dependency() is for */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid job_free(Job *j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->transaction_prev);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->transaction_next);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->subject_list);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->object_list);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->in_run_queue)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(run_queue, j->manager->run_queue, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->in_dbus_queue)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(j->timer_event_source);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus_client_track_free(j->subscribed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid job_uninstall(Job *j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Job **pj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(*pj == j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Detach from next 'bigger' objects */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* daemon-reload should be transparent to job observers */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->manager->n_reloading <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus_job_send_removed_signal(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *pj = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_add_to_gc_queue(j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->installed = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 Poettering return t != JOB_RELOAD;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_merge_into_installed(Job *j, Job *other) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->unit == other->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->type != JOB_NOP)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_type_merge_and_collapse(&j->type, other->type, j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(other->type == JOB_NOP);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringJob* job_install(Job *j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Job **pj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Job *uj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uj = *pj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (uj) {
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 else {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* not conflicting, i.e. mergeable */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 job_merge_into_installed(uj, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(uj->unit->id,
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 return uj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else {
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 job_merge_into_installed(uj, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(uj->unit->id,
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 uj->state = JOB_WAITING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uj->manager->n_running_jobs--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return uj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Install the job */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *pj = j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->installed = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->manager->n_installed_jobs ++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(j->unit->id,
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 return j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint job_install_deserialized(Job *j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Job **pj;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(!j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*pj) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(j->unit->id,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Unit %s already has a job installed. Not installing deserialized job.",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EEXIST;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *pj = j;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->installed = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(j->unit->id,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "Reinstalled deserialized job %s/%s as %u",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringJobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JobDependency *l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(object);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!(l = new0(JobDependency, 1)))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l->subject = subject;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l->object = object;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l->matters = matters;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l->conflicts = conflicts;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (subject)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_PREPEND(subject, subject->subject_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_PREPEND(object, object->object_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid job_dependency_free(JobDependency *l) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l->subject)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(subject, l->subject->subject_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(object, l->object->object_list, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid job_dump(Job *j, FILE*f, const char *prefix) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(f);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!prefix)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering prefix = "";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering fprintf(f,
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->id,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering prefix, j->unit->id, job_type_to_string(j->type),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering prefix, job_state_to_string(j->state),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering prefix, yes_no(j->override),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering prefix, yes_no(j->irreversible));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*
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 *
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 *
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 *
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 *
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 Poettering */
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_START */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*JOB_VERIFY_ACTIVE */ JOB_START,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*JOB_STOP */ -1, -1,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (a == b)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (a < b) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JobType tmp = a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a = b;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b = tmp;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return job_merging_table[(a - 1) * a / 2 + b];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringbool job_type_is_redundant(JobType a, UnitActiveState b) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (a) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_START:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_ACTIVE ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_RELOADING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_STOP:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_INACTIVE ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_FAILED;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_VERIFY_ACTIVE:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_ACTIVE ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_RELOADING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_RELOAD:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_RELOADING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_RESTART:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering b == UNIT_ACTIVATING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_not_reached("Invalid job type");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletarvoid job_type_collapse(JobType *t, Unit *u) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering UnitActiveState s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (*t) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_TRY_RESTART:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = unit_active_state(u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *t = JOB_NOP;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *t = JOB_RESTART;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_RELOAD_OR_START:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = unit_active_state(u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *t = JOB_START;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *t = JOB_RELOAD;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 if (t < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EEXIST;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *a = t;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_type_collapse(a, u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool job_is_runnable(Job *j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Iterator i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Unit *other;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 * type. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* First check if there is an override */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->ignore_order)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->type == JOB_NOP)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->type == JOB_START ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->type == JOB_VERIFY_ACTIVE ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->type == JOB_RELOAD) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (other->job)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Also, if something else is being stopped and we should
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * change state after it, then lets wait. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (other->job &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (other->job->type == JOB_STOP ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering other->job->type == JOB_RESTART))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* This means that for a service a and a service b where b
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * shall be started after a:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *
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 *
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * This has the side effect that restarts are properly
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * synchronized too. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_change_type(Job *j, JobType newtype) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_debug_unit(j->unit->id,
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->type = newtype;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint job_run_and_invalidate(Job *j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint32_t id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Manager *m = j->manager;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->in_run_queue);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering LIST_REMOVE(run_queue, j->manager->run_queue, j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->in_run_queue = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->state != JOB_WAITING)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!job_is_runnable(j))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EAGAIN;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->state = JOB_RUNNING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->n_running_jobs++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_add_to_dbus_queue(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 * valid. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering id = j->id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (j->type) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_START:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = unit_start(j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If this unit cannot be started, then simply wait */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EBADR)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_VERIFY_ACTIVE: {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering UnitActiveState t = unit_active_state(j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (UNIT_IS_ACTIVE_OR_RELOADING(t))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -EALREADY;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (t == UNIT_ACTIVATING)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -EAGAIN;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -EBADR;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_STOP:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_RESTART:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = unit_stop(j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If this unit cannot stopped, then simply wait. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EBADR)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_RELOAD:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = unit_reload(j->unit);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_NOP:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -EALREADY;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_not_reached("Unknown job type");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j = manager_get_job(m, id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == -EALREADY)
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 j->state = JOB_WAITING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering m->n_running_jobs--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = job_finish_and_invalidate(j, JOB_FAILED, true);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t < _JOB_TYPE_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_table = &UNIT_VTABLE(u)->status_message_formats;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!format_table)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t == JOB_START)
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *format;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t < _JOB_TYPE_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (format)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return format;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Return generic strings */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t == JOB_START) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_DONE)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Started %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_FAILED)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Failed to start %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_DEPENDENCY)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Dependency failed for %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_TIMEOUT)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Timed out starting %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_STOP || t == JOB_RESTART) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_DONE)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Stopped %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_FAILED)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Stopped (with error) %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_TIMEOUT)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Timed out stoppping %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_RELOAD) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_DONE)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Reloaded %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_FAILED)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Reload failed for %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (result == JOB_TIMEOUT)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return "Timed out reloading %s.";
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic push
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic ignored "-Wformat-nonliteral"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_print_status_message(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *format;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t < _JOB_TYPE_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t == JOB_START) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!format)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_DONE:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (u->condition_result)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_FAILED:
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 break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_DEPENDENCY:
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 break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_TIMEOUT:
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 break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_STOP || t == JOB_RESTART) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!format)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_TIMEOUT:
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 break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_DONE:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case JOB_FAILED:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_VERIFY_ACTIVE) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 if (result == JOB_SKIPPED)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic pop
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic push
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic ignored "-Wformat-nonliteral"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void job_log_status_message(Unit *u, JobType t, JobResult result) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *format;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char buf[LINE_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(u);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t >= 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(t < _JOB_TYPE_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Skip this if it goes to the console. since we already print
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * to the console anyway... */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (log_on_console())
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format = job_get_status_message_format_try_harder(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!format)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering snprintf(buf, sizeof(buf), format, unit_description(u));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char_array_0(buf);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t == JOB_START) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_id128_t mid;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 u->id,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MESSAGE_ID(mid),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "RESULT=%s", job_result_to_string(result),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "MESSAGE=%s", buf,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (t == JOB_STOP)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->id,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "RESULT=%s", job_result_to_string(result),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "MESSAGE=%s", buf,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (t == JOB_RELOAD)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->id,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "RESULT=%s", job_result_to_string(result),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "MESSAGE=%s", buf,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#pragma GCC diagnostic pop
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Unit *u;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Unit *other;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering JobType t;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Iterator i;
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->installed);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u = j->unit;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t = j->type;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->result = result;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (j->state == JOB_RUNNING)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->manager->n_running_jobs--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_print_status_message(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_log_status_message(u, t, result);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_add_to_dbus_queue(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Patch restart jobs so that they become normal start jobs */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_DONE && t == JOB_RESTART) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_change_type(j, JOB_START);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->state = JOB_WAITING;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_add_to_run_queue(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto finish;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (result == JOB_FAILED || result == JOB_INVALID)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering j->manager->n_failed_jobs ++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_uninstall(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering job_free(j);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
/* Fail depending jobs on failure */
if (result != JOB_DONE && recursive) {
if (t == JOB_START ||
t == JOB_VERIFY_ACTIVE) {
SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
if (other->job &&
(other->job->type == JOB_START ||
other->job->type == JOB_VERIFY_ACTIVE))
job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
if (other->job &&
(other->job->type == JOB_START ||
other->job->type == JOB_VERIFY_ACTIVE))
job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
if (other->job &&
!other->job->override &&
(other->job->type == JOB_START ||
other->job->type == JOB_VERIFY_ACTIVE))
job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
} else if (t == JOB_STOP) {
SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
if (other->job &&
(other->job->type == JOB_START ||
other->job->type == JOB_VERIFY_ACTIVE))
job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
}
}
/* Trigger OnFailure dependencies that are not generated by
* the unit itself. We don't treat JOB_CANCELED as failure in
* this context. And JOB_FAILURE is already handled by the
* unit itself. */
if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
log_struct_unit(LOG_NOTICE,
u->id,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
"Job %s/%s failed with result '%s'.",
u->id,
job_type_to_string(t),
job_result_to_string(result),
NULL);
unit_start_on_failure(u);
}
unit_trigger_notify(u);
finish:
/* Try to start the next jobs that can be started */
SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
if (other->job)
job_add_to_run_queue(other->job);
SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
if (other->job)
job_add_to_run_queue(other->job);
manager_check_finished(u->manager);
return 0;
}
static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) {
Job *j = userdata;
assert(j);
assert(s == j->timer_event_source);
log_warning_unit(j->unit->id, "Job %s/%s timed out.",
j->unit->id, job_type_to_string(j->type));
job_finish_and_invalidate(j, JOB_TIMEOUT, true);
return 0;
}
int job_start_timer(Job *j) {
int r;
if (j->unit->job_timeout <= 0 || j->timer_event_source)
return 0;
j->begin_usec = now(CLOCK_MONOTONIC);
r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source);
if (r < 0)
return r;
return 0;
}
void job_add_to_run_queue(Job *j) {
assert(j);
assert(j->installed);
if (j->in_run_queue)
return;
if (!j->manager->run_queue)
sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
LIST_PREPEND(run_queue, j->manager->run_queue, j);
j->in_run_queue = true;
}
void job_add_to_dbus_queue(Job *j) {
assert(j);
assert(j->installed);
if (j->in_dbus_queue)
return;
/* We don't check if anybody is subscribed here, since this
* job might just have been created and not yet assigned to a
* connection/client. */
LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j);
j->in_dbus_queue = true;
}
char *job_dbus_path(Job *j) {
char *p;
assert(j);
if (asprintf(&p, "/org/freedesktop/systemd1/job/%"PRIu32, j->id) < 0)
return NULL;
return p;
}
int job_serialize(Job *j, FILE *f, FDSet *fds) {
fprintf(f, "job-id=%u\n", j->id);
fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
fprintf(f, "job-override=%s\n", yes_no(j->override));
fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
if (j->begin_usec > 0)
fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
bus_client_track_serialize(j->manager, f, j->subscribed);
/* End marker */
fputc('\n', f);
return 0;
}
int job_deserialize(Job *j, FILE *f, FDSet *fds) {
assert(j);
for (;;) {
char line[LINE_MAX], *l, *v;
size_t k;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
return 0;
return -errno;
}
char_array_0(line);
l = strstrip(line);
/* End marker */
if (l[0] == 0)
return 0;
k = strcspn(l, "=");
if (l[k] == '=') {
l[k] = 0;
v = l+k+1;
} else
v = l+k;
if (streq(l, "job-id")) {
if (safe_atou32(v, &j->id) < 0)
log_debug("Failed to parse job id value %s", v);
} else if (streq(l, "job-type")) {
JobType t;
t = job_type_from_string(v);
if (t < 0)
log_debug("Failed to parse job type %s", v);
else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
log_debug("Cannot deserialize job of type %s", v);
else
j->type = t;
} else if (streq(l, "job-state")) {
JobState s;
s = job_state_from_string(v);
if (s < 0)
log_debug("Failed to parse job state %s", v);
else
j->state = s;
} else if (streq(l, "job-override")) {
int b;
b = parse_boolean(v);
if (b < 0)
log_debug("Failed to parse job override flag %s", v);
else
j->override = j->override || b;
} else if (streq(l, "job-irreversible")) {
int b;
b = parse_boolean(v);
if (b < 0)
log_debug("Failed to parse job irreversible flag %s", v);
else
j->irreversible = j->irreversible || b;
} else if (streq(l, "job-sent-dbus-new-signal")) {
int b;
b = parse_boolean(v);
if (b < 0)
log_debug("Failed to parse job sent_dbus_new_signal flag %s", v);
else
j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
} else if (streq(l, "job-ignore-order")) {
int b;
b = parse_boolean(v);
if (b < 0)
log_debug("Failed to parse job ignore_order flag %s", v);
else
j->ignore_order = j->ignore_order || b;
} else if (streq(l, "job-begin")) {
unsigned long long ull;
if (sscanf(v, "%llu", &ull) != 1)
log_debug("Failed to parse job-begin value %s", v);
else
j->begin_usec = ull;
} else {
char t[strlen(l) + 1 + strlen(v) + 1];
strcpy(stpcpy(stpcpy(t, l), "="), v);
if (bus_client_track_deserialize_item(j->manager, &j->subscribed, t) == 0)
log_debug("Unknown deserialization key '%s'", l);
}
}
}
int job_coldplug(Job *j) {
int r;
assert(j);
if (j->begin_usec <= 0)
return 0;
if (j->timer_event_source)
j->timer_event_source = sd_event_source_unref(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);
if (r < 0)
log_debug("Failed to restart timeout for job: %s", strerror(-r));
return r;
}
void job_shutdown_magic(Job *j) {
assert(j);
/* The shutdown target gets some special treatment here: we
* tell the kernel to begin with flushing its disk caches, to
* optimize shutdown time a bit. Ideally we wouldn't hardcode
* this magic into PID 1. However all other processes aren't
* options either since they'd exit much sooner than PID 1 and
* asynchronous sync() would cause their exit to be
* delayed. */
if (j->type != JOB_START)
return;
if (j->unit->manager->running_as != SYSTEMD_SYSTEM)
return;
if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
return;
/* In case messages on console has been disabled on boot */
j->unit->manager->no_console_output = false;
if (detect_container(NULL) > 0)
return;
asynchronous_sync();
}
int job_get_timeout(Job *j, uint64_t *timeout) {
Unit *u = j->unit;
uint64_t x = -1, y = -1;
int r = 0, q = 0;
assert(u);
if (j->timer_event_source) {
r = sd_event_source_get_time(j->timer_event_source, &x);
if (r < 0)
return r;
r = 1;
}
if (UNIT_VTABLE(u)->get_timeout) {
q = UNIT_VTABLE(u)->get_timeout(u, &y);
if (q < 0)
return q;
}
if (r == 0 && q == 0)
return 0;
*timeout = MIN(x, y);
log_info("job_get_timeout %s %d/%"PRIu64" %d/%"PRIu64" -> 1/%"PRIu64,
j->unit->id, r, x, q, y, *timeout);
return 1;
}
static const char* const job_state_table[_JOB_STATE_MAX] = {
[JOB_WAITING] = "waiting",
[JOB_RUNNING] = "running"
};
DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
static const char* const job_type_table[_JOB_TYPE_MAX] = {
[JOB_START] = "start",
[JOB_VERIFY_ACTIVE] = "verify-active",
[JOB_STOP] = "stop",
[JOB_RELOAD] = "reload",
[JOB_RELOAD_OR_START] = "reload-or-start",
[JOB_RESTART] = "restart",
[JOB_TRY_RESTART] = "try-restart",
[JOB_NOP] = "nop",
};
DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
static const char* const job_mode_table[_JOB_MODE_MAX] = {
[JOB_FAIL] = "fail",
[JOB_REPLACE] = "replace",
[JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
[JOB_ISOLATE] = "isolate",
[JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
[JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
[JOB_FLUSH] = "flush",
};
DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
static const char* const job_result_table[_JOB_RESULT_MAX] = {
[JOB_DONE] = "done",
[JOB_CANCELED] = "canceled",
[JOB_TIMEOUT] = "timeout",
[JOB_FAILED] = "failed",
[JOB_DEPENDENCY] = "dependency",
[JOB_SKIPPED] = "skipped",
[JOB_INVALID] = "invalid",
};
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);