]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/job.c
job: serialize jobs properly
[thirdparty/systemd.git] / src / core / job.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
a7334b09
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275 22#include <assert.h>
1ffba6fe 23#include <errno.h>
faf919f1
LP
24#include <sys/timerfd.h>
25#include <sys/epoll.h>
60918275 26
94f04347
LP
27#include "set.h"
28#include "unit.h"
60918275 29#include "macro.h"
94f04347
LP
30#include "strv.h"
31#include "load-fragment.h"
32#include "load-dropin.h"
f50e0a01 33#include "log.h"
4139c1b2 34#include "dbus-job.h"
60918275 35
97e6a119
MS
36JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) {
37 JobBusClient *cl;
38 size_t name_len;
39
40 name_len = strlen(name);
41 cl = malloc0(sizeof(JobBusClient) + name_len + 1);
42 if (!cl)
43 return NULL;
44
45 cl->bus = connection;
46 memcpy(cl->name, name, name_len + 1);
47 return cl;
48}
49
39a18c60 50Job* job_new_raw(Unit *unit) {
60918275
LP
51 Job *j;
52
39a18c60
MS
53 /* used for deserialization */
54
87f0e418 55 assert(unit);
60918275 56
39a18c60
MS
57 j = new0(Job, 1);
58 if (!j)
60918275
LP
59 return NULL;
60
668ad332 61 j->manager = unit->manager;
87f0e418 62 j->unit = unit;
faf919f1
LP
63 j->timer_watch.type = WATCH_INVALID;
64
39a18c60
MS
65 return j;
66}
67
68Job* job_new(Unit *unit, JobType type) {
69 Job *j;
70
71 assert(type < _JOB_TYPE_MAX);
72
73 j = job_new_raw(unit);
74 if (!j)
75 return NULL;
76
77 j->id = j->manager->current_job_id++;
78 j->type = type;
79
e5b5ae50 80 /* We don't link it here, that's what job_dependency() is for */
60918275
LP
81
82 return j;
83}
84
97e7d748 85void job_free(Job *j) {
97e6a119
MS
86 JobBusClient *cl;
87
97e7d748
MS
88 assert(j);
89 assert(!j->installed);
02a3bcc6
MS
90 assert(!j->transaction_prev);
91 assert(!j->transaction_next);
92 assert(!j->subject_list);
93 assert(!j->object_list);
60918275 94
c1e1601e
LP
95 if (j->in_run_queue)
96 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
97
98 if (j->in_dbus_queue)
99 LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
100
faf919f1
LP
101 if (j->timer_watch.type != WATCH_INVALID) {
102 assert(j->timer_watch.type == WATCH_JOB_TIMER);
103 assert(j->timer_watch.data.job == j);
104 assert(j->timer_watch.fd >= 0);
105
106 assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
107 close_nointr_nofail(j->timer_watch.fd);
108 }
109
97e6a119
MS
110 while ((cl = j->bus_client_list)) {
111 LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
112 free(cl);
113 }
60918275
LP
114 free(j);
115}
a66d02c3 116
05d576f1
MS
117void job_uninstall(Job *j) {
118 assert(j->installed);
d6a093d0 119 assert(j->unit->job == j);
05d576f1
MS
120 /* Detach from next 'bigger' objects */
121
39a18c60
MS
122 /* daemon-reload should be transparent to job observers */
123 if (j->manager->n_reloading <= 0)
124 bus_job_send_removed_signal(j);
05d576f1 125
d6a093d0
MS
126 j->unit->job = NULL;
127 unit_add_to_gc_queue(j->unit);
05d576f1
MS
128
129 hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
130 j->installed = false;
131}
132
656bbffc
MS
133static bool job_type_allows_late_merge(JobType t) {
134 /* Tells whether it is OK to merge a job of type 't' with an already
135 * running job.
136 * Reloads cannot be merged this way. Think of the sequence:
137 * 1. Reload of a daemon is in progress; the daemon has already loaded
138 * its config file, but hasn't completed the reload operation yet.
139 * 2. Edit foo's config file.
140 * 3. Trigger another reload to have the daemon use the new config.
141 * Should the second reload job be merged into the first one, the daemon
142 * would not know about the new config.
143 * JOB_RESTART jobs on the other hand can be merged, because they get
144 * patched into JOB_START after stopping the unit. So if we see a
145 * JOB_RESTART running, it means the unit hasn't stopped yet and at
146 * this time the merge is still allowed. */
147 return !(t == JOB_RELOAD || t == JOB_RELOAD_OR_START);
148}
149
150static void job_merge_into_installed(Job *j, Job *other) {
151 assert(j->installed);
152 assert(j->unit == other->unit);
153
154 j->type = job_type_lookup_merge(j->type, other->type);
155 assert(j->type >= 0);
156
157 j->override = j->override || other->override;
158}
159
160Job* job_install(Job *j) {
05d576f1
MS
161 Job *uj = j->unit->job;
162
656bbffc
MS
163 assert(!j->installed);
164
05d576f1 165 if (uj) {
656bbffc
MS
166 if (job_type_is_conflicting(uj->type, j->type))
167 job_finish_and_invalidate(uj, JOB_CANCELED);
168 else {
169 /* not conflicting, i.e. mergeable */
170
171 if (uj->state == JOB_WAITING ||
172 (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
173 job_merge_into_installed(uj, j);
174 log_debug("Merged into installed job %s/%s as %u",
175 uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
176 return uj;
177 } else {
178 /* already running and not safe to merge into */
179 /* Patch uj to become a merged job and re-run it. */
180 /* XXX It should be safer to queue j to run after uj finishes, but it is
181 * not currently possible to have more than one installed job per unit. */
182 job_merge_into_installed(uj, j);
183 log_debug("Merged into running job, re-running: %s/%s as %u",
184 uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
185 uj->state = JOB_WAITING;
186 return uj;
187 }
188 }
05d576f1
MS
189 }
190
656bbffc 191 /* Install the job */
05d576f1
MS
192 j->unit->job = j;
193 j->installed = true;
194 j->manager->n_installed_jobs ++;
195 log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
656bbffc 196 return j;
05d576f1
MS
197}
198
39a18c60
MS
199void job_install_deserialized(Job *j) {
200 assert(!j->installed);
201
202 if (j->unit->job) {
203 log_debug("Unit %s already has a job installed. Not installing deserialized job.", j->unit->id);
204 return;
205 }
206 j->unit->job = j;
207 j->installed = true;
208 log_debug("Reinstalled deserialized job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
209}
210
1da4264f 211JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
e5b5ae50
LP
212 JobDependency *l;
213
214 assert(object);
215
216 /* Adds a new job link, which encodes that the 'subject' job
217 * needs the 'object' job in some way. If 'subject' is NULL
218 * this means the 'anchor' job (i.e. the one the user
35b8ca3a 219 * explicitly asked for) is the requester. */
e5b5ae50 220
ceed3570 221 if (!(l = new0(JobDependency, 1)))
e5b5ae50
LP
222 return NULL;
223
224 l->subject = subject;
225 l->object = object;
226 l->matters = matters;
69dd2852 227 l->conflicts = conflicts;
e5b5ae50 228
44d8db9e
LP
229 if (subject)
230 LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
e5b5ae50 231
44d8db9e 232 LIST_PREPEND(JobDependency, object, object->object_list, l);
e5b5ae50
LP
233
234 return l;
235}
236
1da4264f 237void job_dependency_free(JobDependency *l) {
e5b5ae50
LP
238 assert(l);
239
44d8db9e
LP
240 if (l->subject)
241 LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
e5b5ae50 242
44d8db9e 243 LIST_REMOVE(JobDependency, object, l->object->object_list, l);
e5b5ae50
LP
244
245 free(l);
246}
247
1ffba6fe 248void job_dump(Job *j, FILE*f, const char *prefix) {
a66d02c3
LP
249 assert(j);
250 assert(f);
251
9eb63b3c
LP
252 if (!prefix)
253 prefix = "";
254
ceed3570 255 fprintf(f,
40d50879
LP
256 "%s-> Job %u:\n"
257 "%s\tAction: %s -> %s\n"
5cb5a6ff
LP
258 "%s\tState: %s\n"
259 "%s\tForced: %s\n",
ceed3570 260 prefix, j->id,
ac155bb8 261 prefix, j->unit->id, job_type_to_string(j->type),
94f04347 262 prefix, job_state_to_string(j->state),
9e2f7c11 263 prefix, yes_no(j->override));
a66d02c3 264}
e5b5ae50 265
348e27fe
MS
266/*
267 * Merging is commutative, so imagine the matrix as symmetric. We store only
268 * its lower triangle to avoid duplication. We don't store the main diagonal,
269 * because A merged with A is simply A.
270 *
271 * Merging is associative! A merged with B merged with C is the same as
272 * A merged with C merged with B.
273 *
274 * Mergeability is transitive! If A can be merged with B and B with C then
275 * A also with C.
276 *
277 * Also, if A merged with B cannot be merged with C, then either A or B cannot
278 * be merged with C either.
279 */
280static const JobType job_merging_table[] = {
281/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD JOB_RELOAD_OR_START JOB_RESTART JOB_TRY_RESTART */
282/************************************************************************************************************************************/
283/*JOB_START */
284/*JOB_VERIFY_ACTIVE */ JOB_START,
285/*JOB_STOP */ -1, -1,
286/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
287/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START,
288/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART, JOB_RESTART,
289/*JOB_TRY_RESTART */ JOB_RESTART, JOB_TRY_RESTART, -1, JOB_TRY_RESTART, JOB_RESTART, JOB_RESTART,
290};
291
292JobType job_type_lookup_merge(JobType a, JobType b) {
293 assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2);
294 assert(a >= 0 && a < _JOB_TYPE_MAX);
295 assert(b >= 0 && b < _JOB_TYPE_MAX);
1ffba6fe
LP
296
297 if (a == b)
348e27fe 298 return a;
1ffba6fe 299
348e27fe
MS
300 if (a < b) {
301 JobType tmp = a;
302 a = b;
303 b = tmp;
1ffba6fe 304 }
e094e853 305
348e27fe 306 return job_merging_table[(a - 1) * a / 2 + b];
e094e853 307}
cd2dbd7d 308
593fbdd2
LP
309bool job_type_is_redundant(JobType a, UnitActiveState b) {
310 switch (a) {
311
312 case JOB_START:
313 return
314 b == UNIT_ACTIVE ||
032ff4af 315 b == UNIT_RELOADING;
593fbdd2
LP
316
317 case JOB_STOP:
318 return
6124958c 319 b == UNIT_INACTIVE ||
fdf20a31 320 b == UNIT_FAILED;
593fbdd2
LP
321
322 case JOB_VERIFY_ACTIVE:
323 return
324 b == UNIT_ACTIVE ||
032ff4af 325 b == UNIT_RELOADING;
593fbdd2
LP
326
327 case JOB_RELOAD:
328 return
032ff4af 329 b == UNIT_RELOADING;
593fbdd2
LP
330
331 case JOB_RELOAD_OR_START:
332 return
333 b == UNIT_ACTIVATING ||
032ff4af 334 b == UNIT_RELOADING;
593fbdd2
LP
335
336 case JOB_RESTART:
337 return
338 b == UNIT_ACTIVATING;
339
340 case JOB_TRY_RESTART:
341 return
342 b == UNIT_ACTIVATING;
343
344 default:
345 assert_not_reached("Invalid job type");
346 }
347}
348
5cb5a6ff 349bool job_is_runnable(Job *j) {
034c6ed7 350 Iterator i;
87f0e418 351 Unit *other;
5cb5a6ff
LP
352
353 assert(j);
ac1135be 354 assert(j->installed);
5cb5a6ff 355
87f0e418 356 /* Checks whether there is any job running for the units this
5cb5a6ff 357 * job needs to be running after (in the case of a 'positive'
e67c3609
LP
358 * job type) or before (in the case of a 'negative' job
359 * type. */
360
361 /* First check if there is an override */
cebe0d41 362 if (j->ignore_order)
e67c3609 363 return true;
5cb5a6ff
LP
364
365 if (j->type == JOB_START ||
366 j->type == JOB_VERIFY_ACTIVE ||
367 j->type == JOB_RELOAD ||
368 j->type == JOB_RELOAD_OR_START) {
369
370 /* Immediate result is that the job is or might be
371 * started. In this case lets wait for the
372 * dependencies, regardless whether they are
373 * starting or stopping something. */
374
ac155bb8
MS
375 SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
376 if (other->job)
5cb5a6ff
LP
377 return false;
378 }
379
380 /* Also, if something else is being stopped and we should
381 * change state after it, then lets wait. */
382
ac155bb8
MS
383 SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
384 if (other->job &&
385 (other->job->type == JOB_STOP ||
386 other->job->type == JOB_RESTART ||
387 other->job->type == JOB_TRY_RESTART))
5cb5a6ff
LP
388 return false;
389
390 /* This means that for a service a and a service b where b
391 * shall be started after a:
392 *
393 * start a + start b → 1st step start a, 2nd step start b
394 * start a + stop b → 1st step stop b, 2nd step start a
395 * stop a + start b → 1st step stop a, 2nd step start b
396 * stop a + stop b → 1st step stop b, 2nd step stop a
397 *
398 * This has the side effect that restarts are properly
399 * synchronized too. */
400
401 return true;
402}
403
bbd1a837
MS
404static void job_change_type(Job *j, JobType newtype) {
405 log_debug("Converting job %s/%s -> %s/%s",
406 j->unit->id, job_type_to_string(j->type),
407 j->unit->id, job_type_to_string(newtype));
408
409 j->type = newtype;
410}
411
5cb5a6ff
LP
412int job_run_and_invalidate(Job *j) {
413 int r;
2cf19a7a
LP
414 uint32_t id;
415 Manager *m;
ac1135be 416
5cb5a6ff 417 assert(j);
ac1135be 418 assert(j->installed);
5cb5a6ff 419
034c6ed7
LP
420 if (j->in_run_queue) {
421 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
422 j->in_run_queue = false;
423 }
5cb5a6ff
LP
424
425 if (j->state != JOB_WAITING)
426 return 0;
427
034c6ed7
LP
428 if (!job_is_runnable(j))
429 return -EAGAIN;
430
83c60c9f 431 j->state = JOB_RUNNING;
c1e1601e 432 job_add_to_dbus_queue(j);
83c60c9f 433
2cf19a7a
LP
434 /* While we execute this operation the job might go away (for
435 * example: because it is replaced by a new, conflicting
436 * job.) To make sure we don't access a freed job later on we
437 * store the id here, so that we can verify the job is still
438 * valid. */
439 id = j->id;
440 m = j->manager;
441
5cb5a6ff
LP
442 switch (j->type) {
443
dd17d388
MS
444 case JOB_RELOAD_OR_START:
445 if (unit_active_state(j->unit) == UNIT_ACTIVE) {
bbd1a837 446 job_change_type(j, JOB_RELOAD);
dd17d388
MS
447 r = unit_reload(j->unit);
448 break;
449 }
bbd1a837 450 job_change_type(j, JOB_START);
dd17d388
MS
451 /* fall through */
452
5cb5a6ff 453 case JOB_START:
87f0e418 454 r = unit_start(j->unit);
57339f47 455
dd17d388 456 /* If this unit cannot be started, then simply wait */
5cb5a6ff
LP
457 if (r == -EBADR)
458 r = 0;
459 break;
460
461 case JOB_VERIFY_ACTIVE: {
87f0e418
LP
462 UnitActiveState t = unit_active_state(j->unit);
463 if (UNIT_IS_ACTIVE_OR_RELOADING(t))
5cb5a6ff 464 r = -EALREADY;
87f0e418 465 else if (t == UNIT_ACTIVATING)
5cb5a6ff
LP
466 r = -EAGAIN;
467 else
468 r = -ENOEXEC;
469 break;
470 }
471
dd17d388
MS
472 case JOB_TRY_RESTART:
473 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) {
474 r = -ENOEXEC;
475 break;
476 }
bbd1a837 477 job_change_type(j, JOB_RESTART);
dd17d388
MS
478 /* fall through */
479
5cb5a6ff 480 case JOB_STOP:
dd17d388 481 case JOB_RESTART:
87f0e418 482 r = unit_stop(j->unit);
57339f47 483
dd17d388 484 /* If this unit cannot stopped, then simply wait. */
57339f47
LP
485 if (r == -EBADR)
486 r = 0;
5cb5a6ff
LP
487 break;
488
489 case JOB_RELOAD:
87f0e418 490 r = unit_reload(j->unit);
5cb5a6ff
LP
491 break;
492
5cb5a6ff 493 default:
44d8db9e 494 assert_not_reached("Unknown job type");
5cb5a6ff
LP
495 }
496
2cf19a7a
LP
497 if ((j = manager_get_job(m, id))) {
498 if (r == -EALREADY)
5d44db4a 499 r = job_finish_and_invalidate(j, JOB_DONE);
d68201e9
LP
500 else if (r == -ENOEXEC)
501 r = job_finish_and_invalidate(j, JOB_SKIPPED);
2cf19a7a
LP
502 else if (r == -EAGAIN)
503 j->state = JOB_WAITING;
504 else if (r < 0)
5d44db4a 505 r = job_finish_and_invalidate(j, JOB_FAILED);
2cf19a7a 506 }
5cb5a6ff
LP
507
508 return r;
509}
510
e02cd6f7
LP
511static void job_print_status_message(Unit *u, JobType t, JobResult result) {
512 assert(u);
513
514 if (t == JOB_START) {
515
516 switch (result) {
517
518 case JOB_DONE:
69120666 519 if (u->condition_result)
78ff1acd 520 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Started %s.", unit_description(u));
e02cd6f7
LP
521 break;
522
523 case JOB_FAILED:
78ff1acd 524 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s.", unit_description(u));
ac155bb8 525 unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
e02cd6f7
LP
526 break;
527
528 case JOB_DEPENDENCY:
78ff1acd 529 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s.", unit_description(u));
e02cd6f7
LP
530 break;
531
532 case JOB_TIMEOUT:
78ff1acd 533 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s.", unit_description(u));
e02cd6f7
LP
534 break;
535
536 default:
537 ;
538 }
539
540 } else if (t == JOB_STOP) {
541
542 switch (result) {
543
544 case JOB_TIMEOUT:
78ff1acd 545 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s.", unit_description(u));
e02cd6f7
LP
546 break;
547
548 case JOB_DONE:
549 case JOB_FAILED:
78ff1acd 550 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Stopped %s.", unit_description(u));
e02cd6f7
LP
551 break;
552
553 default:
554 ;
555 }
556 }
557}
558
5d44db4a 559int job_finish_and_invalidate(Job *j, JobResult result) {
87f0e418
LP
560 Unit *u;
561 Unit *other;
b866264a 562 JobType t;
034c6ed7 563 Iterator i;
563ba9ea 564 bool recursed = false;
5cb5a6ff
LP
565
566 assert(j);
ac1135be 567 assert(j->installed);
5cb5a6ff 568
c1e1601e 569 job_add_to_dbus_queue(j);
f50e0a01 570
034c6ed7 571 /* Patch restart jobs so that they become normal start jobs */
dd17d388 572 if (result == JOB_DONE && j->type == JOB_RESTART) {
f50e0a01 573
bbd1a837 574 job_change_type(j, JOB_START);
9c2d9caa 575 j->state = JOB_WAITING;
cc42e081
LP
576
577 job_add_to_run_queue(j);
57981b98
LP
578
579 u = j->unit;
580 goto finish;
5cb5a6ff
LP
581 }
582
5d44db4a 583 j->result = result;
76bf48b7 584
ac155bb8 585 log_debug("Job %s/%s finished, result=%s", j->unit->id, job_type_to_string(j->type), job_result_to_string(result));
9c2d9caa 586
5d44db4a 587 if (result == JOB_FAILED)
76bf48b7
LP
588 j->manager->n_failed_jobs ++;
589
87f0e418 590 u = j->unit;
5cb5a6ff 591 t = j->type;
97e7d748 592 job_uninstall(j);
5cb5a6ff
LP
593 job_free(j);
594
e02cd6f7 595 job_print_status_message(u, t, result);
9e58ff9c 596
5cb5a6ff 597 /* Fail depending jobs on failure */
5d44db4a 598 if (result != JOB_DONE) {
5cb5a6ff
LP
599
600 if (t == JOB_START ||
601 t == JOB_VERIFY_ACTIVE ||
602 t == JOB_RELOAD_OR_START) {
603
ac155bb8
MS
604 SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
605 if (other->job &&
606 (other->job->type == JOB_START ||
607 other->job->type == JOB_VERIFY_ACTIVE ||
608 other->job->type == JOB_RELOAD_OR_START)) {
609 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
610 recursed = true;
611 }
5cb5a6ff 612
ac155bb8
MS
613 SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
614 if (other->job &&
615 (other->job->type == JOB_START ||
616 other->job->type == JOB_VERIFY_ACTIVE ||
617 other->job->type == JOB_RELOAD_OR_START)) {
618 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
619 recursed = true;
620 }
e6a3ff95 621
ac155bb8
MS
622 SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
623 if (other->job &&
624 !other->job->override &&
625 (other->job->type == JOB_START ||
626 other->job->type == JOB_VERIFY_ACTIVE ||
627 other->job->type == JOB_RELOAD_OR_START)) {
628 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
629 recursed = true;
630 }
5cb5a6ff
LP
631
632 } else if (t == JOB_STOP) {
633
ac155bb8
MS
634 SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
635 if (other->job &&
636 (other->job->type == JOB_START ||
637 other->job->type == JOB_VERIFY_ACTIVE ||
638 other->job->type == JOB_RELOAD_OR_START)) {
639 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
640 recursed = true;
641 }
5cb5a6ff
LP
642 }
643 }
644
c0daa706
LP
645 /* Trigger OnFailure dependencies that are not generated by
646 * the unit itself. We don't tread JOB_CANCELED as failure in
647 * this context. And JOB_FAILURE is already handled by the
648 * unit itself. */
222ae6a8
LP
649 if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
650 log_notice("Job %s/%s failed with result '%s'.",
ac155bb8 651 u->id,
222ae6a8
LP
652 job_type_to_string(t),
653 job_result_to_string(result));
654
c0daa706 655 unit_trigger_on_failure(u);
222ae6a8 656 }
c0daa706 657
57981b98 658finish:
5cb5a6ff 659 /* Try to start the next jobs that can be started */
ac155bb8
MS
660 SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
661 if (other->job)
662 job_add_to_run_queue(other->job);
663 SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
664 if (other->job)
665 job_add_to_run_queue(other->job);
5cb5a6ff 666
ac155bb8 667 manager_check_finished(u->manager);
b0c918b9 668
563ba9ea 669 return recursed;
5cb5a6ff 670}
034c6ed7 671
faf919f1
LP
672int job_start_timer(Job *j) {
673 struct itimerspec its;
674 struct epoll_event ev;
675 int fd, r;
676 assert(j);
677
ac155bb8 678 if (j->unit->job_timeout <= 0 ||
faf919f1
LP
679 j->timer_watch.type == WATCH_JOB_TIMER)
680 return 0;
681
682 assert(j->timer_watch.type == WATCH_INVALID);
683
684 if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
685 r = -errno;
686 goto fail;
687 }
688
689 zero(its);
ac155bb8 690 timespec_store(&its.it_value, j->unit->job_timeout);
faf919f1
LP
691
692 if (timerfd_settime(fd, 0, &its, NULL) < 0) {
693 r = -errno;
694 goto fail;
695 }
696
697 zero(ev);
698 ev.data.ptr = &j->timer_watch;
699 ev.events = EPOLLIN;
700
701 if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
702 r = -errno;
703 goto fail;
704 }
705
706 j->timer_watch.type = WATCH_JOB_TIMER;
707 j->timer_watch.fd = fd;
708 j->timer_watch.data.job = j;
709
710 return 0;
711
712fail:
713 if (fd >= 0)
714 close_nointr_nofail(fd);
715
716 return r;
717}
718
c1e1601e 719void job_add_to_run_queue(Job *j) {
034c6ed7 720 assert(j);
ac1135be 721 assert(j->installed);
034c6ed7
LP
722
723 if (j->in_run_queue)
724 return;
725
726 LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
727 j->in_run_queue = true;
728}
94f04347 729
c1e1601e
LP
730void job_add_to_dbus_queue(Job *j) {
731 assert(j);
732 assert(j->installed);
733
734 if (j->in_dbus_queue)
735 return;
736
a567261a
LP
737 /* We don't check if anybody is subscribed here, since this
738 * job might just have been created and not yet assigned to a
739 * connection/client. */
94b6dfa2 740
c1e1601e
LP
741 LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
742 j->in_dbus_queue = true;
743}
744
ea430986
LP
745char *job_dbus_path(Job *j) {
746 char *p;
747
748 assert(j);
749
750 if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
751 return NULL;
752
753 return p;
754}
755
faf919f1
LP
756void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
757 assert(j);
758 assert(w == &j->timer_watch);
759
ac155bb8 760 log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
5d44db4a 761 job_finish_and_invalidate(j, JOB_TIMEOUT);
faf919f1
LP
762}
763
39a18c60
MS
764int job_serialize(Job *j, FILE *f, FDSet *fds) {
765 fprintf(f, "job-id=%u\n", j->id);
766 fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
767 fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
768 fprintf(f, "job-override=%s\n", yes_no(j->override));
769 fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
770 fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
771 /* Cannot save bus clients. Just note the fact that we're losing
772 * them. job_send_message() will fallback to broadcasting. */
773 fprintf(f, "job-forgot-bus-clients=%s\n",
774 yes_no(j->forgot_bus_clients || j->bus_client_list));
775 if (j->timer_watch.type == WATCH_JOB_TIMER) {
776 int copy = fdset_put_dup(fds, j->timer_watch.fd);
777 if (copy < 0)
778 return copy;
779 fprintf(f, "job-timer-watch-fd=%d\n", copy);
780 }
781
782 /* End marker */
783 fputc('\n', f);
784 return 0;
785}
786
787int job_deserialize(Job *j, FILE *f, FDSet *fds) {
788 for (;;) {
789 char line[LINE_MAX], *l, *v;
790 size_t k;
791
792 if (!fgets(line, sizeof(line), f)) {
793 if (feof(f))
794 return 0;
795 return -errno;
796 }
797
798 char_array_0(line);
799 l = strstrip(line);
800
801 /* End marker */
802 if (l[0] == 0)
803 return 0;
804
805 k = strcspn(l, "=");
806
807 if (l[k] == '=') {
808 l[k] = 0;
809 v = l+k+1;
810 } else
811 v = l+k;
812
813 if (streq(l, "job-id")) {
814 if (safe_atou32(v, &j->id) < 0)
815 log_debug("Failed to parse job id value %s", v);
816 } else if (streq(l, "job-type")) {
817 JobType t = job_type_from_string(v);
818 if (t < 0)
819 log_debug("Failed to parse job type %s", v);
820 else
821 j->type = t;
822 } else if (streq(l, "job-state")) {
823 JobState s = job_state_from_string(v);
824 if (s < 0)
825 log_debug("Failed to parse job state %s", v);
826 else
827 j->state = s;
828 } else if (streq(l, "job-override")) {
829 int b = parse_boolean(v);
830 if (b < 0)
831 log_debug("Failed to parse job override flag %s", v);
832 else
833 j->override = j->override || b;
834 } else if (streq(l, "job-sent-dbus-new-signal")) {
835 int b = parse_boolean(v);
836 if (b < 0)
837 log_debug("Failed to parse job sent_dbus_new_signal flag %s", v);
838 else
839 j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
840 } else if (streq(l, "job-ignore-order")) {
841 int b = parse_boolean(v);
842 if (b < 0)
843 log_debug("Failed to parse job ignore_order flag %s", v);
844 else
845 j->ignore_order = j->ignore_order || b;
846 } else if (streq(l, "job-forgot-bus-clients")) {
847 int b = parse_boolean(v);
848 if (b < 0)
849 log_debug("Failed to parse job forgot_bus_clients flag %s", v);
850 else
851 j->forgot_bus_clients = j->forgot_bus_clients || b;
852 } else if (streq(l, "job-timer-watch-fd")) {
853 int fd;
854 if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
855 log_debug("Failed to parse job-timer-watch-fd value %s", v);
856 else {
857 if (j->timer_watch.type == WATCH_JOB_TIMER)
858 close_nointr_nofail(j->timer_watch.fd);
859
860 j->timer_watch.type = WATCH_JOB_TIMER;
861 j->timer_watch.fd = fdset_remove(fds, fd);
862 j->timer_watch.data.job = j;
863 }
864 }
865 }
866}
867
868int job_coldplug(Job *j) {
869 struct epoll_event ev;
870
871 if (j->timer_watch.type != WATCH_JOB_TIMER)
872 return 0;
873
874 zero(ev);
875 ev.data.ptr = &j->timer_watch;
876 ev.events = EPOLLIN;
877
878 if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, j->timer_watch.fd, &ev) < 0)
879 return -errno;
880
881 return 0;
882}
883
94f04347
LP
884static const char* const job_state_table[_JOB_STATE_MAX] = {
885 [JOB_WAITING] = "waiting",
886 [JOB_RUNNING] = "running"
887};
888
889DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
890
891static const char* const job_type_table[_JOB_TYPE_MAX] = {
892 [JOB_START] = "start",
893 [JOB_VERIFY_ACTIVE] = "verify-active",
894 [JOB_STOP] = "stop",
895 [JOB_RELOAD] = "reload",
896 [JOB_RELOAD_OR_START] = "reload-or-start",
897 [JOB_RESTART] = "restart",
898 [JOB_TRY_RESTART] = "try-restart",
899};
900
901DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
b548631a
LP
902
903static const char* const job_mode_table[_JOB_MODE_MAX] = {
904 [JOB_FAIL] = "fail",
c497c7a9 905 [JOB_REPLACE] = "replace",
e67c3609 906 [JOB_ISOLATE] = "isolate",
cebe0d41
LP
907 [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
908 [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
b548631a
LP
909};
910
911DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
5d44db4a
LP
912
913static const char* const job_result_table[_JOB_RESULT_MAX] = {
914 [JOB_DONE] = "done",
915 [JOB_CANCELED] = "canceled",
916 [JOB_TIMEOUT] = "timeout",
917 [JOB_FAILED] = "failed",
d68201e9
LP
918 [JOB_DEPENDENCY] = "dependency",
919 [JOB_SKIPPED] = "skipped"
5d44db4a
LP
920};
921
922DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);