job.c revision ead8e4788ee31bbdc38b4cd3c6e71c8a95bbc95a
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen/***
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering This file is part of systemd.
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering Copyright 2010 Lennart Poettering
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering systemd is free software; you can redistribute it and/or modify it
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering under the terms of the GNU General Public License as published by
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering the Free Software Foundation; either version 2 of the License, or
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering (at your option) any later version.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering systemd is distributed in the hope that it will be useful, but
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering General Public License for more details.
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU General Public License
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering***/
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering#include <assert.h>
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering#include <errno.h>
56ba3c78ae35065064c4289a0c8e22a81256af20Zbigniew Jędrzejewski-Szmek#include <sys/timerfd.h>
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering#include <sys/epoll.h>
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "set.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "unit.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "macro.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "strv.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "load-fragment.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "load-dropin.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "log.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#include "dbus-job.h"
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-SzmekJob* job_new(Manager *m, JobType type, Unit *unit) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek Job *j;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(m);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(type < _JOB_TYPE_MAX);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(unit);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!(j = new0(Job, 1)))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek j->manager = m;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek j->id = m->current_job_id++;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering j->type = type;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek j->unit = unit;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek j->timer_watch.type = WATCH_INVALID;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* We don't link it here, that's what job_dependency() is for */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return j;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid job_free(Job *j) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(j);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Detach from next 'bigger' objects */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (j->installed) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek bus_job_send_removed_signal(j, !j->failed);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (j->unit->meta.job == j) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek j->unit->meta.job = NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_add_to_gc_queue(j->unit);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek j->installed = false;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering }
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering /* Detach from next 'smaller' objects */
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering manager_transaction_unlink_job(j->manager, j, true);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (j->in_run_queue)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (j->in_dbus_queue)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (j->timer_watch.type != WATCH_INVALID) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(j->timer_watch.type == WATCH_JOB_TIMER);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(j->timer_watch.data.job == j);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(j->timer_watch.fd >= 0);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek close_nointr_nofail(j->timer_watch.fd);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek free(j->bus_client);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek free(j);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-SzmekJobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek JobDependency *l;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(object);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Adds a new job link, which encodes that the 'subject' job
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * needs the 'object' job in some way. If 'subject' is NULL
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * this means the 'anchor' job (i.e. the one the user
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * explcitily asked for) is the requester. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!(l = new0(JobDependency, 1)))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return NULL;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek l->subject = subject;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek l->object = object;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek l->matters = matters;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek l->conflicts = conflicts;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (subject)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek else
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_PREPEND(JobDependency, subject, object->manager->transaction_anchor, l);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_PREPEND(JobDependency, object, object->object_list, l);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return l;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekvoid job_dependency_free(JobDependency *l) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(l);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (l->subject)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek else
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering LIST_REMOVE(JobDependency, subject, l->object->manager->transaction_anchor, l);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering LIST_REMOVE(JobDependency, object, l->object->object_list, l);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering free(l);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering}
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poetteringvoid job_dump(Job *j, FILE*f, const char *prefix) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering assert(j);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering assert(f);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering if (!prefix)
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering prefix = "";
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering fprintf(f,
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering "%s-> Job %u:\n"
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering "%s\tAction: %s -> %s\n"
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering "%s\tState: %s\n"
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering "%s\tForced: %s\n",
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering prefix, j->id,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek prefix, j->unit->meta.id, job_type_to_string(j->type),
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek prefix, job_state_to_string(j->state),
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek prefix, yes_no(j->override));
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekbool job_is_anchor(Job *j) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek JobDependency *l;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering assert(j);
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering LIST_FOREACH(object, l, j->object_list)
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering if (!l->subject)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return true;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return false;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic bool types_match(JobType a, JobType b, JobType c, JobType d) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek (a == c && b == d) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek (a == d && b == c);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekint job_type_merge(JobType *a, JobType b) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (*a == b)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return 0;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Merging is associative! a merged with b merged with c is
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * the same as a merged with c merged with b. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Mergeability is transitive! if a can be merged with b and b
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * with c then a also with c */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Also, if a merged with b cannot be merged with c, then
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * either a or b cannot be merged with c either */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (types_match(*a, b, JOB_START, JOB_VERIFY_ACTIVE))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *a = JOB_START;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek else if (types_match(*a, b, JOB_START, JOB_RELOAD) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_START, JOB_RELOAD_OR_START) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD_OR_START) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_RELOAD, JOB_RELOAD_OR_START))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek *a = JOB_RELOAD_OR_START;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek else if (types_match(*a, b, JOB_START, JOB_RESTART) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_START, JOB_TRY_RESTART) ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RESTART) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_RELOAD, JOB_RESTART) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_RELOAD_OR_START, JOB_RESTART) ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek types_match(*a, b, JOB_RELOAD_OR_START, JOB_TRY_RESTART) ||
667c24a6a86a5a26a906b7477ae81dcf4c73e64eLennart Poettering types_match(*a, b, JOB_RESTART, JOB_TRY_RESTART))
667c24a6a86a5a26a906b7477ae81dcf4c73e64eLennart Poettering *a = JOB_RESTART;
667c24a6a86a5a26a906b7477ae81dcf4c73e64eLennart Poettering else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_RELOAD))
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering *a = JOB_RELOAD;
667c24a6a86a5a26a906b7477ae81dcf4c73e64eLennart Poettering else if (types_match(*a, b, JOB_VERIFY_ACTIVE, JOB_TRY_RESTART) ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering types_match(*a, b, JOB_RELOAD, JOB_TRY_RESTART))
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering *a = JOB_TRY_RESTART;
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering else
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering return -EEXIST;
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering
667c24a6a86a5a26a906b7477ae81dcf4c73e64eLennart Poettering return 0;
667c24a6a86a5a26a906b7477ae81dcf4c73e64eLennart Poettering}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekbool job_type_is_mergeable(JobType a, JobType b) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return job_type_merge(&a, b) >= 0;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekbool job_type_is_superset(JobType a, JobType b) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Checks whether operation a is a "superset" of b in its
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * actions */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (a == b)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return true;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek switch (a) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_START:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return b == JOB_VERIFY_ACTIVE;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_RELOAD:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == JOB_VERIFY_ACTIVE;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_RELOAD_OR_START:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == JOB_RELOAD ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == JOB_START ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == JOB_VERIFY_ACTIVE;
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering case JOB_RESTART:
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering return
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering b == JOB_START ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering b == JOB_VERIFY_ACTIVE ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering b == JOB_RELOAD ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering b == JOB_RELOAD_OR_START ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering b == JOB_TRY_RESTART;
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering case JOB_TRY_RESTART:
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering return
7ca4155737730ece73ae4b4ac80571005cb99b69Jan Engelhardt b == JOB_VERIFY_ACTIVE ||
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering b == JOB_RELOAD;
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering default:
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering return false;
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering }
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering}
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poetteringbool job_type_is_conflicting(JobType a, JobType b) {
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering assert(a >= 0 && a < _JOB_TYPE_MAX);
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering assert(b >= 0 && b < _JOB_TYPE_MAX);
707b66c66381c899d7ef640e158ffdd5bcff4debLennart Poettering
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return (a == JOB_STOP) != (b == JOB_STOP);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek}
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekbool job_type_is_redundant(JobType a, UnitActiveState b) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek switch (a) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_START:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_ACTIVE ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_RELOADING;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_STOP:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_INACTIVE ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_FAILED;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_VERIFY_ACTIVE:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_ACTIVE ||
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_RELOADING;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_RELOAD:
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek return
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek b == UNIT_RELOADING;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek case JOB_RELOAD_OR_START:
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering return
0b3b020a178cf3b957fed627de13c895773995ecLennart Poettering b == UNIT_ACTIVATING ||
b == UNIT_RELOADING;
case JOB_RESTART:
return
b == UNIT_ACTIVATING;
case JOB_TRY_RESTART:
return
b == UNIT_ACTIVATING;
default:
assert_not_reached("Invalid job type");
}
}
bool job_is_runnable(Job *j) {
Iterator i;
Unit *other;
assert(j);
assert(j->installed);
/* Checks whether there is any job running for the units this
* job needs to be running after (in the case of a 'positive'
* job type) or before (in the case of a 'negative' job type
* . */
if (j->type == JOB_START ||
j->type == JOB_VERIFY_ACTIVE ||
j->type == JOB_RELOAD ||
j->type == JOB_RELOAD_OR_START) {
/* Immediate result is that the job is or might be
* started. In this case lets wait for the
* dependencies, regardless whether they are
* starting or stopping something. */
SET_FOREACH(other, j->unit->meta.dependencies[UNIT_AFTER], i)
if (other->meta.job)
return false;
}
/* Also, if something else is being stopped and we should
* change state after it, then lets wait. */
SET_FOREACH(other, j->unit->meta.dependencies[UNIT_BEFORE], i)
if (other->meta.job &&
(other->meta.job->type == JOB_STOP ||
other->meta.job->type == JOB_RESTART ||
other->meta.job->type == JOB_TRY_RESTART))
return false;
/* This means that for a service a and a service b where b
* shall be started after a:
*
* start a + start b → 1st step start a, 2nd step start b
* start a + stop b → 1st step stop b, 2nd step start a
* stop a + start b → 1st step stop a, 2nd step start b
* stop a + stop b → 1st step stop b, 2nd step stop a
*
* This has the side effect that restarts are properly
* synchronized too. */
return true;
}
int job_run_and_invalidate(Job *j) {
int r;
uint32_t id;
Manager *m;
assert(j);
assert(j->installed);
if (j->in_run_queue) {
LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
j->in_run_queue = false;
}
if (j->state != JOB_WAITING)
return 0;
if (!job_is_runnable(j))
return -EAGAIN;
j->state = JOB_RUNNING;
job_add_to_dbus_queue(j);
/* While we execute this operation the job might go away (for
* example: because it is replaced by a new, conflicting
* job.) To make sure we don't access a freed job later on we
* store the id here, so that we can verify the job is still
* valid. */
id = j->id;
m = j->manager;
switch (j->type) {
case JOB_START:
r = unit_start(j->unit);
if (r == -EBADR)
r = 0;
break;
case JOB_VERIFY_ACTIVE: {
UnitActiveState t = unit_active_state(j->unit);
if (UNIT_IS_ACTIVE_OR_RELOADING(t))
r = -EALREADY;
else if (t == UNIT_ACTIVATING)
r = -EAGAIN;
else
r = -ENOEXEC;
break;
}
case JOB_STOP:
r = unit_stop(j->unit);
break;
case JOB_RELOAD:
r = unit_reload(j->unit);
break;
case JOB_RELOAD_OR_START:
if (unit_active_state(j->unit) == UNIT_ACTIVE)
r = unit_reload(j->unit);
else
r = unit_start(j->unit);
break;
case JOB_RESTART: {
UnitActiveState t = unit_active_state(j->unit);
if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_ACTIVATING) {
j->type = JOB_START;
r = unit_start(j->unit);
} else
r = unit_stop(j->unit);
break;
}
case JOB_TRY_RESTART: {
UnitActiveState t = unit_active_state(j->unit);
if (t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING)
r = -ENOEXEC;
else if (t == UNIT_ACTIVATING) {
j->type = JOB_START;
r = unit_start(j->unit);
} else
r = unit_stop(j->unit);
break;
}
default:
assert_not_reached("Unknown job type");
}
if ((j = manager_get_job(m, id))) {
if (r == -EALREADY)
r = job_finish_and_invalidate(j, true);
else if (r == -EAGAIN)
j->state = JOB_WAITING;
else if (r < 0)
r = job_finish_and_invalidate(j, false);
}
return r;
}
int job_finish_and_invalidate(Job *j, bool success) {
Unit *u;
Unit *other;
JobType t;
Iterator i;
assert(j);
assert(j->installed);
job_add_to_dbus_queue(j);
/* Patch restart jobs so that they become normal start jobs */
if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
log_debug("Converting job %s/%s -> %s/%s",
j->unit->meta.id, job_type_to_string(j->type),
j->unit->meta.id, job_type_to_string(JOB_START));
j->state = JOB_WAITING;
j->type = JOB_START;
job_add_to_run_queue(j);
return 0;
}
j->failed = !success;
log_debug("Job %s/%s finished, success=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(success));
if (j->failed)
j->manager->n_failed_jobs ++;
u = j->unit;
t = j->type;
job_free(j);
if (!success && j->type == JOB_START)
unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u));
/* Fail depending jobs on failure */
if (!success) {
if (t == JOB_START ||
t == JOB_VERIFY_ACTIVE ||
t == JOB_RELOAD_OR_START) {
SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
if (other->meta.job &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
other->meta.job->type == JOB_RELOAD_OR_START))
job_finish_and_invalidate(other->meta.job, false);
SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
if (other->meta.job &&
!other->meta.job->override &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
other->meta.job->type == JOB_RELOAD_OR_START))
job_finish_and_invalidate(other->meta.job, false);
} else if (t == JOB_STOP) {
SET_FOREACH(other, u->meta.dependencies[UNIT_CONFLICTS], i)
if (other->meta.job &&
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
other->meta.job->type == JOB_RELOAD_OR_START))
job_finish_and_invalidate(other->meta.job, false);
}
}
/* Try to start the next jobs that can be started */
SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
if (other->meta.job)
job_add_to_run_queue(other->meta.job);
SET_FOREACH(other, u->meta.dependencies[UNIT_BEFORE], i)
if (other->meta.job)
job_add_to_run_queue(other->meta.job);
manager_check_finished(u->meta.manager);
return 0;
}
int job_start_timer(Job *j) {
struct itimerspec its;
struct epoll_event ev;
int fd, r;
assert(j);
if (j->unit->meta.job_timeout <= 0 ||
j->timer_watch.type == WATCH_JOB_TIMER)
return 0;
assert(j->timer_watch.type == WATCH_INVALID);
if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
r = -errno;
goto fail;
}
zero(its);
timespec_store(&its.it_value, j->unit->meta.job_timeout);
if (timerfd_settime(fd, 0, &its, NULL) < 0) {
r = -errno;
goto fail;
}
zero(ev);
ev.data.ptr = &j->timer_watch;
ev.events = EPOLLIN;
if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
r = -errno;
goto fail;
}
j->timer_watch.type = WATCH_JOB_TIMER;
j->timer_watch.fd = fd;
j->timer_watch.data.job = j;
return 0;
fail:
if (fd >= 0)
close_nointr_nofail(fd);
return r;
}
void job_add_to_run_queue(Job *j) {
assert(j);
assert(j->installed);
if (j->in_run_queue)
return;
LIST_PREPEND(Job, 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(Job, 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/%lu", (unsigned long) j->id) < 0)
return NULL;
return p;
}
void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
assert(j);
assert(w == &j->timer_watch);
log_warning("Job %s/%s timed out.", j->unit->meta.id, job_type_to_string(j->type));
job_finish_and_invalidate(j, false);
}
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",
};
DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
static const char* const job_mode_table[_JOB_MODE_MAX] = {
[JOB_FAIL] = "fail",
[JOB_REPLACE] = "replace",
[JOB_ISOLATE] = "isolate"
};
DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);