1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/timerfd.h>
25 #include <sys/epoll.h>
31 #include "load-fragment.h"
32 #include "load-dropin.h"
36 Job
* job_new(Manager
*m
, JobType type
, Unit
*unit
) {
40 assert(type
< _JOB_TYPE_MAX
);
43 if (!(j
= new0(Job
, 1)))
47 j
->id
= m
->current_job_id
++;
51 j
->timer_watch
.type
= WATCH_INVALID
;
53 /* We don't link it here, that's what job_dependency() is for */
58 void job_free(Job
*j
) {
61 /* Detach from next 'bigger' objects */
63 bus_job_send_removed_signal(j
);
65 if (j
->unit
->job
== j
) {
67 unit_add_to_gc_queue(j
->unit
);
70 hashmap_remove(j
->manager
->jobs
, UINT32_TO_PTR(j
->id
));
74 assert(!j
->transaction_prev
);
75 assert(!j
->transaction_next
);
76 assert(!j
->subject_list
);
77 assert(!j
->object_list
);
80 LIST_REMOVE(Job
, run_queue
, j
->manager
->run_queue
, j
);
83 LIST_REMOVE(Job
, dbus_queue
, j
->manager
->dbus_job_queue
, j
);
85 if (j
->timer_watch
.type
!= WATCH_INVALID
) {
86 assert(j
->timer_watch
.type
== WATCH_JOB_TIMER
);
87 assert(j
->timer_watch
.data
.job
== j
);
88 assert(j
->timer_watch
.fd
>= 0);
90 assert_se(epoll_ctl(j
->manager
->epoll_fd
, EPOLL_CTL_DEL
, j
->timer_watch
.fd
, NULL
) >= 0);
91 close_nointr_nofail(j
->timer_watch
.fd
);
98 JobDependency
* job_dependency_new(Job
*subject
, Job
*object
, bool matters
, bool conflicts
) {
103 /* Adds a new job link, which encodes that the 'subject' job
104 * needs the 'object' job in some way. If 'subject' is NULL
105 * this means the 'anchor' job (i.e. the one the user
106 * explicitly asked for) is the requester. */
108 if (!(l
= new0(JobDependency
, 1)))
111 l
->subject
= subject
;
113 l
->matters
= matters
;
114 l
->conflicts
= conflicts
;
117 LIST_PREPEND(JobDependency
, subject
, subject
->subject_list
, l
);
119 LIST_PREPEND(JobDependency
, subject
, object
->manager
->transaction_anchor
, l
);
121 LIST_PREPEND(JobDependency
, object
, object
->object_list
, l
);
126 void job_dependency_free(JobDependency
*l
) {
130 LIST_REMOVE(JobDependency
, subject
, l
->subject
->subject_list
, l
);
132 LIST_REMOVE(JobDependency
, subject
, l
->object
->manager
->transaction_anchor
, l
);
134 LIST_REMOVE(JobDependency
, object
, l
->object
->object_list
, l
);
139 void job_dump(Job
*j
, FILE*f
, const char *prefix
) {
148 "%s\tAction: %s -> %s\n"
152 prefix
, j
->unit
->id
, job_type_to_string(j
->type
),
153 prefix
, job_state_to_string(j
->state
),
154 prefix
, yes_no(j
->override
));
157 bool job_is_anchor(Job
*j
) {
162 LIST_FOREACH(object
, l
, j
->object_list
)
170 * Merging is commutative, so imagine the matrix as symmetric. We store only
171 * its lower triangle to avoid duplication. We don't store the main diagonal,
172 * because A merged with A is simply A.
174 * Merging is associative! A merged with B merged with C is the same as
175 * A merged with C merged with B.
177 * Mergeability is transitive! If A can be merged with B and B with C then
180 * Also, if A merged with B cannot be merged with C, then either A or B cannot
181 * be merged with C either.
183 static const JobType job_merging_table
[] = {
184 /* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD JOB_RELOAD_OR_START JOB_RESTART JOB_TRY_RESTART */
185 /************************************************************************************************************************************/
187 /*JOB_VERIFY_ACTIVE */ JOB_START
,
188 /*JOB_STOP */ -1, -1,
189 /*JOB_RELOAD */ JOB_RELOAD_OR_START
, JOB_RELOAD
, -1,
190 /*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START
, JOB_RELOAD_OR_START
, -1, JOB_RELOAD_OR_START
,
191 /*JOB_RESTART */ JOB_RESTART
, JOB_RESTART
, -1, JOB_RESTART
, JOB_RESTART
,
192 /*JOB_TRY_RESTART */ JOB_RESTART
, JOB_TRY_RESTART
, -1, JOB_TRY_RESTART
, JOB_RESTART
, JOB_RESTART
,
195 JobType
job_type_lookup_merge(JobType a
, JobType b
) {
196 assert_cc(ELEMENTSOF(job_merging_table
) == _JOB_TYPE_MAX
* (_JOB_TYPE_MAX
- 1) / 2);
197 assert(a
>= 0 && a
< _JOB_TYPE_MAX
);
198 assert(b
>= 0 && b
< _JOB_TYPE_MAX
);
209 return job_merging_table
[(a
- 1) * a
/ 2 + b
];
212 bool job_type_is_redundant(JobType a
, UnitActiveState b
) {
222 b
== UNIT_INACTIVE
||
225 case JOB_VERIFY_ACTIVE
:
234 case JOB_RELOAD_OR_START
:
236 b
== UNIT_ACTIVATING
||
241 b
== UNIT_ACTIVATING
;
243 case JOB_TRY_RESTART
:
245 b
== UNIT_ACTIVATING
;
248 assert_not_reached("Invalid job type");
252 bool job_is_runnable(Job
*j
) {
257 assert(j
->installed
);
259 /* Checks whether there is any job running for the units this
260 * job needs to be running after (in the case of a 'positive'
261 * job type) or before (in the case of a 'negative' job
264 /* First check if there is an override */
268 if (j
->type
== JOB_START
||
269 j
->type
== JOB_VERIFY_ACTIVE
||
270 j
->type
== JOB_RELOAD
||
271 j
->type
== JOB_RELOAD_OR_START
) {
273 /* Immediate result is that the job is or might be
274 * started. In this case lets wait for the
275 * dependencies, regardless whether they are
276 * starting or stopping something. */
278 SET_FOREACH(other
, j
->unit
->dependencies
[UNIT_AFTER
], i
)
283 /* Also, if something else is being stopped and we should
284 * change state after it, then lets wait. */
286 SET_FOREACH(other
, j
->unit
->dependencies
[UNIT_BEFORE
], i
)
288 (other
->job
->type
== JOB_STOP
||
289 other
->job
->type
== JOB_RESTART
||
290 other
->job
->type
== JOB_TRY_RESTART
))
293 /* This means that for a service a and a service b where b
294 * shall be started after a:
296 * start a + start b → 1st step start a, 2nd step start b
297 * start a + stop b → 1st step stop b, 2nd step start a
298 * stop a + start b → 1st step stop a, 2nd step start b
299 * stop a + stop b → 1st step stop b, 2nd step stop a
301 * This has the side effect that restarts are properly
302 * synchronized too. */
307 static void job_change_type(Job
*j
, JobType newtype
) {
308 log_debug("Converting job %s/%s -> %s/%s",
309 j
->unit
->id
, job_type_to_string(j
->type
),
310 j
->unit
->id
, job_type_to_string(newtype
));
315 int job_run_and_invalidate(Job
*j
) {
321 assert(j
->installed
);
323 if (j
->in_run_queue
) {
324 LIST_REMOVE(Job
, run_queue
, j
->manager
->run_queue
, j
);
325 j
->in_run_queue
= false;
328 if (j
->state
!= JOB_WAITING
)
331 if (!job_is_runnable(j
))
334 j
->state
= JOB_RUNNING
;
335 job_add_to_dbus_queue(j
);
337 /* While we execute this operation the job might go away (for
338 * example: because it is replaced by a new, conflicting
339 * job.) To make sure we don't access a freed job later on we
340 * store the id here, so that we can verify the job is still
347 case JOB_RELOAD_OR_START
:
348 if (unit_active_state(j
->unit
) == UNIT_ACTIVE
) {
349 job_change_type(j
, JOB_RELOAD
);
350 r
= unit_reload(j
->unit
);
353 job_change_type(j
, JOB_START
);
357 r
= unit_start(j
->unit
);
359 /* If this unit cannot be started, then simply wait */
364 case JOB_VERIFY_ACTIVE
: {
365 UnitActiveState t
= unit_active_state(j
->unit
);
366 if (UNIT_IS_ACTIVE_OR_RELOADING(t
))
368 else if (t
== UNIT_ACTIVATING
)
375 case JOB_TRY_RESTART
:
376 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j
->unit
))) {
380 job_change_type(j
, JOB_RESTART
);
385 r
= unit_stop(j
->unit
);
387 /* If this unit cannot stopped, then simply wait. */
393 r
= unit_reload(j
->unit
);
397 assert_not_reached("Unknown job type");
400 if ((j
= manager_get_job(m
, id
))) {
402 r
= job_finish_and_invalidate(j
, JOB_DONE
);
403 else if (r
== -ENOEXEC
)
404 r
= job_finish_and_invalidate(j
, JOB_SKIPPED
);
405 else if (r
== -EAGAIN
)
406 j
->state
= JOB_WAITING
;
408 r
= job_finish_and_invalidate(j
, JOB_FAILED
);
414 static void job_print_status_message(Unit
*u
, JobType t
, JobResult result
) {
417 if (t
== JOB_START
) {
422 if (u
->condition_result
)
423 unit_status_printf(u
, ANSI_HIGHLIGHT_GREEN_ON
" OK " ANSI_HIGHLIGHT_OFF
, "Started %s", unit_description(u
));
427 unit_status_printf(u
, ANSI_HIGHLIGHT_RED_ON
"FAILED" ANSI_HIGHLIGHT_OFF
, "Failed to start %s", unit_description(u
));
428 unit_status_printf(u
, NULL
, "See 'systemctl status %s' for details.", u
->id
);
432 unit_status_printf(u
, ANSI_HIGHLIGHT_RED_ON
" ABORT" ANSI_HIGHLIGHT_OFF
, "Dependency failed. Aborted start of %s", unit_description(u
));
436 unit_status_printf(u
, ANSI_HIGHLIGHT_RED_ON
" TIME " ANSI_HIGHLIGHT_OFF
, "Timed out starting %s", unit_description(u
));
443 } else if (t
== JOB_STOP
) {
448 unit_status_printf(u
, ANSI_HIGHLIGHT_RED_ON
" TIME " ANSI_HIGHLIGHT_OFF
, "Timed out stopping %s", unit_description(u
));
453 unit_status_printf(u
, ANSI_HIGHLIGHT_GREEN_ON
" OK " ANSI_HIGHLIGHT_OFF
, "Stopped %s", unit_description(u
));
462 int job_finish_and_invalidate(Job
*j
, JobResult result
) {
467 bool recursed
= false;
470 assert(j
->installed
);
472 job_add_to_dbus_queue(j
);
474 /* Patch restart jobs so that they become normal start jobs */
475 if (result
== JOB_DONE
&& j
->type
== JOB_RESTART
) {
477 job_change_type(j
, JOB_START
);
478 j
->state
= JOB_WAITING
;
480 job_add_to_run_queue(j
);
488 log_debug("Job %s/%s finished, result=%s", j
->unit
->id
, job_type_to_string(j
->type
), job_result_to_string(result
));
490 if (result
== JOB_FAILED
)
491 j
->manager
->n_failed_jobs
++;
497 job_print_status_message(u
, t
, result
);
499 /* Fail depending jobs on failure */
500 if (result
!= JOB_DONE
) {
502 if (t
== JOB_START
||
503 t
== JOB_VERIFY_ACTIVE
||
504 t
== JOB_RELOAD_OR_START
) {
506 SET_FOREACH(other
, u
->dependencies
[UNIT_REQUIRED_BY
], i
)
508 (other
->job
->type
== JOB_START
||
509 other
->job
->type
== JOB_VERIFY_ACTIVE
||
510 other
->job
->type
== JOB_RELOAD_OR_START
)) {
511 job_finish_and_invalidate(other
->job
, JOB_DEPENDENCY
);
515 SET_FOREACH(other
, u
->dependencies
[UNIT_BOUND_BY
], i
)
517 (other
->job
->type
== JOB_START
||
518 other
->job
->type
== JOB_VERIFY_ACTIVE
||
519 other
->job
->type
== JOB_RELOAD_OR_START
)) {
520 job_finish_and_invalidate(other
->job
, JOB_DEPENDENCY
);
524 SET_FOREACH(other
, u
->dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
], i
)
526 !other
->job
->override
&&
527 (other
->job
->type
== JOB_START
||
528 other
->job
->type
== JOB_VERIFY_ACTIVE
||
529 other
->job
->type
== JOB_RELOAD_OR_START
)) {
530 job_finish_and_invalidate(other
->job
, JOB_DEPENDENCY
);
534 } else if (t
== JOB_STOP
) {
536 SET_FOREACH(other
, u
->dependencies
[UNIT_CONFLICTED_BY
], i
)
538 (other
->job
->type
== JOB_START
||
539 other
->job
->type
== JOB_VERIFY_ACTIVE
||
540 other
->job
->type
== JOB_RELOAD_OR_START
)) {
541 job_finish_and_invalidate(other
->job
, JOB_DEPENDENCY
);
547 /* Trigger OnFailure dependencies that are not generated by
548 * the unit itself. We don't tread JOB_CANCELED as failure in
549 * this context. And JOB_FAILURE is already handled by the
551 if (result
== JOB_TIMEOUT
|| result
== JOB_DEPENDENCY
) {
552 log_notice("Job %s/%s failed with result '%s'.",
554 job_type_to_string(t
),
555 job_result_to_string(result
));
557 unit_trigger_on_failure(u
);
561 /* Try to start the next jobs that can be started */
562 SET_FOREACH(other
, u
->dependencies
[UNIT_AFTER
], i
)
564 job_add_to_run_queue(other
->job
);
565 SET_FOREACH(other
, u
->dependencies
[UNIT_BEFORE
], i
)
567 job_add_to_run_queue(other
->job
);
569 manager_check_finished(u
->manager
);
574 int job_start_timer(Job
*j
) {
575 struct itimerspec its
;
576 struct epoll_event ev
;
580 if (j
->unit
->job_timeout
<= 0 ||
581 j
->timer_watch
.type
== WATCH_JOB_TIMER
)
584 assert(j
->timer_watch
.type
== WATCH_INVALID
);
586 if ((fd
= timerfd_create(CLOCK_MONOTONIC
, TFD_NONBLOCK
|TFD_CLOEXEC
)) < 0) {
592 timespec_store(&its
.it_value
, j
->unit
->job_timeout
);
594 if (timerfd_settime(fd
, 0, &its
, NULL
) < 0) {
600 ev
.data
.ptr
= &j
->timer_watch
;
603 if (epoll_ctl(j
->manager
->epoll_fd
, EPOLL_CTL_ADD
, fd
, &ev
) < 0) {
608 j
->timer_watch
.type
= WATCH_JOB_TIMER
;
609 j
->timer_watch
.fd
= fd
;
610 j
->timer_watch
.data
.job
= j
;
616 close_nointr_nofail(fd
);
621 void job_add_to_run_queue(Job
*j
) {
623 assert(j
->installed
);
628 LIST_PREPEND(Job
, run_queue
, j
->manager
->run_queue
, j
);
629 j
->in_run_queue
= true;
632 void job_add_to_dbus_queue(Job
*j
) {
634 assert(j
->installed
);
636 if (j
->in_dbus_queue
)
639 /* We don't check if anybody is subscribed here, since this
640 * job might just have been created and not yet assigned to a
641 * connection/client. */
643 LIST_PREPEND(Job
, dbus_queue
, j
->manager
->dbus_job_queue
, j
);
644 j
->in_dbus_queue
= true;
647 char *job_dbus_path(Job
*j
) {
652 if (asprintf(&p
, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j
->id
) < 0)
658 void job_timer_event(Job
*j
, uint64_t n_elapsed
, Watch
*w
) {
660 assert(w
== &j
->timer_watch
);
662 log_warning("Job %s/%s timed out.", j
->unit
->id
, job_type_to_string(j
->type
));
663 job_finish_and_invalidate(j
, JOB_TIMEOUT
);
666 static const char* const job_state_table
[_JOB_STATE_MAX
] = {
667 [JOB_WAITING
] = "waiting",
668 [JOB_RUNNING
] = "running"
671 DEFINE_STRING_TABLE_LOOKUP(job_state
, JobState
);
673 static const char* const job_type_table
[_JOB_TYPE_MAX
] = {
674 [JOB_START
] = "start",
675 [JOB_VERIFY_ACTIVE
] = "verify-active",
677 [JOB_RELOAD
] = "reload",
678 [JOB_RELOAD_OR_START
] = "reload-or-start",
679 [JOB_RESTART
] = "restart",
680 [JOB_TRY_RESTART
] = "try-restart",
683 DEFINE_STRING_TABLE_LOOKUP(job_type
, JobType
);
685 static const char* const job_mode_table
[_JOB_MODE_MAX
] = {
687 [JOB_REPLACE
] = "replace",
688 [JOB_ISOLATE
] = "isolate",
689 [JOB_IGNORE_DEPENDENCIES
] = "ignore-dependencies",
690 [JOB_IGNORE_REQUIREMENTS
] = "ignore-requirements"
693 DEFINE_STRING_TABLE_LOOKUP(job_mode
, JobMode
);
695 static const char* const job_result_table
[_JOB_RESULT_MAX
] = {
697 [JOB_CANCELED
] = "canceled",
698 [JOB_TIMEOUT
] = "timeout",
699 [JOB_FAILED
] = "failed",
700 [JOB_DEPENDENCY
] = "dependency",
701 [JOB_SKIPPED
] = "skipped"
704 DEFINE_STRING_TABLE_LOOKUP(job_result
, JobResult
);