job.c revision cb8ccb2271727fc114ca43104d3333ee4635cc79
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/***
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering This file is part of systemd.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Copyright 2010 Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is free software; you can redistribute it and/or modify it
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering under the terms of the GNU Lesser General Public License as published by
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (at your option) any later version.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is distributed in the hope that it will be useful, but
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Lesser General Public License for more details.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering You should have received a copy of the GNU Lesser General Public License
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering***/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <assert.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/timerfd.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <sys/epoll.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "sd-id128.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "sd-messages.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "set.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "unit.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "macro.h"
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "strv.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "load-fragment.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "load-dropin.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "log.h"
0d39fa9c69b97a2ceb156053deef69c0866c2b97Lennart Poettering#include "dbus-job.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "special.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "async.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "virt.h"
5f311f8c0e51e2f13773823feb6a71f7c6f2838cLennart Poettering#include "dbus-client-track.h"
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart PoetteringJob* job_new_raw(Unit *unit) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Job *j;
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering /* used for deserialization */
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(unit);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j = new0(Job, 1);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!j)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->manager = unit->manager;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->unit = unit;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->type = _JOB_TYPE_INVALID;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return j;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart PoetteringJob* job_new(Unit *unit, JobType type) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering Job *j;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(type < _JOB_TYPE_MAX);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j = job_new_raw(unit);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!j)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return NULL;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->id = j->manager->current_job_id++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->type = type;
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* We don't link it here, that's what job_dependency() is for */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen return j;
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid job_free(Job *j) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt assert(j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(!j->installed);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(!j->transaction_prev);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(!j->transaction_next);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(!j->subject_list);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(!j->object_list);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (j->in_run_queue)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_REMOVE(run_queue, j->manager->run_queue, j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (j->in_dbus_queue)
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_event_source_unref(j->timer_event_source);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt bus_client_track_free(j->subscribed);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt free(j);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid job_uninstall(Job *j) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Job **pj;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j->installed);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(*pj == j);
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Detach from next 'bigger' objects */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* daemon-reload should be transparent to job observers */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (j->manager->n_reloading <= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering bus_job_send_removed_signal(j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *pj = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_add_to_gc_queue(j->unit);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->installed = false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic bool job_type_allows_late_merge(JobType t) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek /* Tells whether it is OK to merge a job of type 't' with an already
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek * running job.
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek * Reloads cannot be merged this way. Think of the sequence:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek * 1. Reload of a daemon is in progress; the daemon has already loaded
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering * its config file, but hasn't completed the reload operation yet.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * 2. Edit foo's config file.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * 3. Trigger another reload to have the daemon use the new config.
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek * Should the second reload job be merged into the first one, the daemon
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek * would not know about the new config.
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek * JOB_RESTART jobs on the other hand can be merged, because they get
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * patched into JOB_START after stopping the unit. So if we see a
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek * JOB_RESTART running, it means the unit hasn't stopped yet and at
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek * this time the merge is still allowed. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return t != JOB_RELOAD;
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic void job_merge_into_installed(Job *j, Job *other) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j->installed);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert(j->unit == other->unit);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (j->type != JOB_NOP)
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek job_type_merge_and_collapse(&j->type, other->type, j->unit);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek else
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert(other->type == JOB_NOP);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek j->override = j->override || other->override;
4b8268f843b0da1cfe1995d93a0b1f95faccc454Zbigniew Jędrzejewski-Szmek j->irreversible = j->irreversible || other->irreversible;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek j->ignore_order = j->ignore_order || other->ignore_order;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek}
4b8268f843b0da1cfe1995d93a0b1f95faccc454Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-SzmekJob* job_install(Job *j) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek Job **pj;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek Job *uj;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert(!j->installed);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek uj = *pj;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (uj) {
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek job_finish_and_invalidate(uj, JOB_CANCELED, false);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek else {
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek /* not conflicting, i.e. mergeable */
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (j->type == JOB_NOP || uj->state == JOB_WAITING ||
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek job_merge_into_installed(uj, j);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek log_debug_unit(uj->unit->id,
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek "Merged into installed job %s/%s as %u",
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return uj;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek } else {
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek /* already running and not safe to merge into */
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek /* Patch uj to become a merged job and re-run it. */
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek /* XXX It should be safer to queue j to run after uj finishes, but it is
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek * not currently possible to have more than one installed job per unit. */
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek job_merge_into_installed(uj, j);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek log_debug_unit(uj->unit->id,
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek "Merged into running job, re-running: %s/%s as %u",
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek uj->state = JOB_WAITING;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek uj->manager->n_running_jobs--;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return uj;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek }
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek }
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek }
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek /* Install the job */
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek *pj = j;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek j->installed = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->manager->n_installed_jobs ++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug_unit(j->unit->id,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "Installed new job %s/%s as %u",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return j;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint job_install_deserialized(Job *j) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Job **pj;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(!j->installed);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek if (*pj) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek log_debug_unit(j->unit->id,
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek "Unit %s already has a job installed. Not installing deserialized job.",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->unit->id);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EEXIST;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *pj = j;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->installed = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug_unit(j->unit->id,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "Reinstalled deserialized job %s/%s as %u",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringJobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering JobDependency *l;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(object);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Adds a new job link, which encodes that the 'subject' job
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * needs the 'object' job in some way. If 'subject' is NULL
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * this means the 'anchor' job (i.e. the one the user
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * explicitly asked for) is the requester. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!(l = new0(JobDependency, 1)))
d3b6d0c21ea5a0d15ec6dbd8b8d179138b7463bcZbigniew Jędrzejewski-Szmek return NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering l->subject = subject;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering l->object = object;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering l->matters = matters;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering l->conflicts = conflicts;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (subject)
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek LIST_PREPEND(subject, subject->subject_list, l);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_PREPEND(object, object->object_list, l);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return l;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmekvoid job_dependency_free(JobDependency *l) {
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek assert(l);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (l->subject)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_REMOVE(subject, l->subject->subject_list, l);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek LIST_REMOVE(object, l->object->object_list, l);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering free(l);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek}
97b11eedff9d2e17101ad453caf9e48b73246719David Herrmann
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringvoid job_dump(Job *j, FILE*f, const char *prefix) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(f);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!prefix)
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek prefix = "";
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek fprintf(f,
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek "%s-> Job %u:\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%s\tAction: %s -> %s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%s\tState: %s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%s\tForced: %s\n"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "%s\tIrreversible: %s\n",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, j->id,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, j->unit->id, job_type_to_string(j->type),
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek prefix, job_state_to_string(j->state),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, yes_no(j->override),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering prefix, yes_no(j->irreversible));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * Merging is commutative, so imagine the matrix as symmetric. We store only
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * its lower triangle to avoid duplication. We don't store the main diagonal,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * because A merged with A is simply A.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * If the resulting type is collapsed immediately afterwards (to get rid of
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * the following properties hold:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * Merging is associative! A merged with B merged with C is the same as
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * A merged with C merged with B.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * Mergeability is transitive! If A can be merged with B and B with C then
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * A also with C.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * Also, if A merged with B cannot be merged with C, then either A or B cannot
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * be merged with C either.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic const JobType job_merging_table[] = {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*********************************************************************************/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*JOB_START */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*JOB_VERIFY_ACTIVE */ JOB_START,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*JOB_STOP */ -1, -1,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering};
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringJobType job_type_lookup_merge(JobType a, JobType b) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (a == b)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return a;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (a < b) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering JobType tmp = a;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering a = b;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b = tmp;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return job_merging_table[(a - 1) * a / 2 + b];
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekbool job_type_is_redundant(JobType a, UnitActiveState b) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek switch (a) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek case JOB_START:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b == UNIT_ACTIVE ||
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b == UNIT_RELOADING;
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt case JOB_STOP:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b == UNIT_INACTIVE ||
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt b == UNIT_FAILED;
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt case JOB_VERIFY_ACTIVE:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b == UNIT_ACTIVE ||
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b == UNIT_RELOADING;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek case JOB_RELOAD:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek b == UNIT_RELOADING;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek case JOB_RESTART:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek b == UNIT_ACTIVATING;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek default:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert_not_reached("Invalid job type");
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekvoid job_type_collapse(JobType *t, Unit *u) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek UnitActiveState s;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek switch (*t) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek case JOB_TRY_RESTART:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek s = unit_active_state(u);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek *t = JOB_NOP;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek else
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering *t = JOB_RESTART;
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering break;
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek case JOB_RELOAD_OR_START:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek s = unit_active_state(u);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek *t = JOB_START;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek else
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek *t = JOB_RELOAD;
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering break;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek default:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek ;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poetteringint job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek JobType t = job_type_lookup_merge(*a, b);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (t < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return -EEXIST;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek *a = t;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering job_type_collapse(a, u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic bool job_is_runnable(Job *j) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Iterator i;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Unit *other;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j->installed);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Checks whether there is any job running for the units this
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek * job needs to be running after (in the case of a 'positive'
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek * job type) or before (in the case of a 'negative' job
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * type. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Note that unit types have a say in what is runnable,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * too. For example, if they return -EAGAIN from
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek * unit_start() they can indicate they are not
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * runnable yet. */
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* First check if there is an override */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (j->ignore_order)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek if (j->type == JOB_NOP)
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek return true;
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering if (j->type == JOB_START ||
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek j->type == JOB_VERIFY_ACTIVE ||
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek j->type == JOB_RELOAD) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Immediate result is that the job is or might be
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * started. In this case lets wait for the
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * dependencies, regardless whether they are
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * starting or stopping something. */
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (other->job)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Also, if something else is being stopped and we should
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * change state after it, then lets wait. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (other->job &&
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (other->job->type == JOB_STOP ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering other->job->type == JOB_RESTART))
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek return false;
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek /* This means that for a service a and a service b where b
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * shall be started after a:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering *
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * start a + start b → 1st step start a, 2nd step start b
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * start a + stop b → 1st step stop b, 2nd step start a
7ff7394d9e4e9189c30fd018235e6b1728c6f2d0Zbigniew Jędrzejewski-Szmek * stop a + start b → 1st step stop a, 2nd step start b
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * stop a + stop b → 1st step stop b, 2nd step stop a
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek *
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek * This has the side effect that restarts are properly
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt * synchronized too. */
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return true;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic void job_change_type(Job *j, JobType newtype) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_debug_unit(j->unit->id,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering "Converting job %s/%s -> %s/%s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->unit->id, job_type_to_string(j->type),
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek j->unit->id, job_type_to_string(newtype));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->type = newtype;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint job_run_and_invalidate(Job *j) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint32_t id;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Manager *m = j->manager;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j->installed);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(j->in_run_queue);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering LIST_REMOVE(run_queue, j->manager->run_queue, j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->in_run_queue = false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering if (j->state != JOB_WAITING)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!job_is_runnable(j))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EAGAIN;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j->state = JOB_RUNNING;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering m->n_running_jobs++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering job_add_to_dbus_queue(j);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* While we execute this operation the job might go away (for
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering * example: because it is replaced by a new, conflicting
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * job.) To make sure we don't access a freed job later on we
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * store the id here, so that we can verify the job is still
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering * valid. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering id = j->id;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering switch (j->type) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_START:
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering r = unit_start(j->unit);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering /* If this unit cannot be started, then simply wait */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r == -EBADR)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_VERIFY_ACTIVE: {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering UnitActiveState t = unit_active_state(j->unit);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (UNIT_IS_ACTIVE_OR_RELOADING(t))
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = -EALREADY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (t == UNIT_ACTIVATING)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = -EAGAIN;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = -EBADR;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_STOP:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_RESTART:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = unit_stop(j->unit);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* If this unit cannot stopped, then simply wait. */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r == -EBADR)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering case JOB_RELOAD:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = unit_reload(j->unit);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_NOP:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = -EALREADY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering default:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_not_reached("Unknown job type");
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering j = manager_get_job(m, id);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (j) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering if (r == -EALREADY)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = job_finish_and_invalidate(j, JOB_DONE, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (r == -EBADR)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (r == -ENOEXEC)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = job_finish_and_invalidate(j, JOB_INVALID, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (r == -EAGAIN) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering j->state = JOB_WAITING;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering m->n_running_jobs--;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering } else if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = job_finish_and_invalidate(j, JOB_FAILED, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
a7f7d1bde43fc825c49afea3f946f5b4b3d563e0Harald Hoyer
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering const UnitStatusMessageFormats *format_table;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(t >= 0);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(t < _JOB_TYPE_MAX);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering format_table = &UNIT_VTABLE(u)->status_message_formats;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!format_table)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (t == JOB_START)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return format_table->finished_start_job[result];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (t == JOB_STOP || t == JOB_RESTART)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return format_table->finished_stop_job[result];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering const char *format;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(u);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(t >= 0);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(t < _JOB_TYPE_MAX);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering format = job_get_status_message_format(u, t, result);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (format)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return format;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* Return generic strings */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (t == JOB_START) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (result == JOB_DONE)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Started %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_FAILED)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Failed to start %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_DEPENDENCY)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Dependency failed for %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_TIMEOUT)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Timed out starting %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (t == JOB_STOP || t == JOB_RESTART) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (result == JOB_DONE)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Stopped %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_FAILED)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Stopped (with error) %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_TIMEOUT)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Timed out stoppping %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (t == JOB_RELOAD) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (result == JOB_DONE)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Reloaded %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_FAILED)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Reload failed for %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else if (result == JOB_TIMEOUT)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return "Timed out reloading %s.";
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return NULL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek}
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek#pragma GCC diagnostic push
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek#pragma GCC diagnostic ignored "-Wformat-nonliteral"
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmekstatic void job_print_status_message(Unit *u, JobType t, JobResult result) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek const char *format;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(u);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(t >= 0);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(t < _JOB_TYPE_MAX);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (t == JOB_START) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek format = job_get_status_message_format(u, t, result);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (!format)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch (result) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_DONE:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (u->condition_result)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_FAILED:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering manager_flip_auto_status(u->manager, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek manager_status_printf(u->manager, false, NULL, "See 'systemctl status %s' for details.", u->id);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_DEPENDENCY:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering manager_flip_auto_status(u->manager, true);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case JOB_TIMEOUT:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering manager_flip_auto_status(u->manager, true);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering default:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering ;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else if (t == JOB_STOP || t == JOB_RESTART) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering format = job_get_status_message_format(u, t, result);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!format)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch (result) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek case JOB_TIMEOUT:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek manager_flip_auto_status(u->manager, true);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek break;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek case JOB_DONE:
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek case JOB_FAILED:
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer break;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek default:
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek ;
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering }
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek } else if (t == JOB_VERIFY_ACTIVE) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek /* When verify-active detects the unit is inactive, report it.
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek * Most likely a DEPEND warning from a requisiting unit will
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek * occur next and it's nice to see what was requisited. */
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (result == JOB_SKIPPED)
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering }
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn}
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek#pragma GCC diagnostic pop
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek#pragma GCC diagnostic push
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek#pragma GCC diagnostic ignored "-Wformat-nonliteral"
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmekstatic void job_log_status_message(Unit *u, JobType t, JobResult result) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek const char *format;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek char buf[LINE_MAX];
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
/* Skip this if it goes to the console. since we already print
* to the console anyway... */
if (log_on_console())
return;
format = job_get_status_message_format_try_harder(u, t, result);
if (!format)
return;
snprintf(buf, sizeof(buf), format, unit_description(u));
char_array_0(buf);
if (t == JOB_START) {
sd_id128_t mid;
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
u->id,
MESSAGE_ID(mid),
"RESULT=%s", job_result_to_string(result),
"MESSAGE=%s", buf,
NULL);
} else if (t == JOB_STOP)
log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
u->id,
MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
"RESULT=%s", job_result_to_string(result),
"MESSAGE=%s", buf,
NULL);
else if (t == JOB_RELOAD)
log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
u->id,
MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
"RESULT=%s", job_result_to_string(result),
"MESSAGE=%s", buf,
NULL);
}
#pragma GCC diagnostic pop
int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
Unit *u;
Unit *other;
JobType t;
Iterator i;
assert(j);
assert(j->installed);
assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
u = j->unit;
t = j->type;
j->result = result;
if (j->state == JOB_RUNNING)
j->manager->n_running_jobs--;
log_debug_unit(u->id, "Job %s/%s finished, result=%s",
u->id, job_type_to_string(t), job_result_to_string(result));
job_print_status_message(u, t, result);
job_log_status_message(u, t, result);
job_add_to_dbus_queue(j);
/* Patch restart jobs so that they become normal start jobs */
if (result == JOB_DONE && t == JOB_RESTART) {
job_change_type(j, JOB_START);
j->state = JOB_WAITING;
job_add_to_run_queue(j);
goto finish;
}
if (result == JOB_FAILED || result == JOB_INVALID)
j->manager->n_failed_jobs ++;
job_uninstall(j);
job_free(j);
/* 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->timer_event_source)
return 0;
j->begin_usec = now(CLOCK_MONOTONIC);
if (j->unit->job_timeout <= 0)
return 0;
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);