]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/job.c
manager: split transaction.[ch]
[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
87f0e418 36Job* job_new(Manager *m, JobType type, Unit *unit) {
60918275
LP
37 Job *j;
38
39 assert(m);
40 assert(type < _JOB_TYPE_MAX);
87f0e418 41 assert(unit);
60918275
LP
42
43 if (!(j = new0(Job, 1)))
44 return NULL;
45
46 j->manager = m;
47 j->id = m->current_job_id++;
48 j->type = type;
87f0e418 49 j->unit = unit;
60918275 50
faf919f1
LP
51 j->timer_watch.type = WATCH_INVALID;
52
e5b5ae50 53 /* We don't link it here, that's what job_dependency() is for */
60918275
LP
54
55 return j;
56}
57
97e7d748
MS
58void job_uninstall(Job *j) {
59 assert(j->installed);
60918275 60 /* Detach from next 'bigger' objects */
c1e1601e 61
97e7d748 62 bus_job_send_removed_signal(j);
60918275 63
97e7d748
MS
64 if (j->unit->job == j) {
65 j->unit->job = NULL;
66 unit_add_to_gc_queue(j->unit);
60918275
LP
67 }
68
97e7d748
MS
69 hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
70 j->installed = false;
71}
72
73void job_free(Job *j) {
74 assert(j);
75 assert(!j->installed);
02a3bcc6
MS
76 assert(!j->transaction_prev);
77 assert(!j->transaction_next);
78 assert(!j->subject_list);
79 assert(!j->object_list);
60918275 80
c1e1601e
LP
81 if (j->in_run_queue)
82 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
83
84 if (j->in_dbus_queue)
85 LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
86
faf919f1
LP
87 if (j->timer_watch.type != WATCH_INVALID) {
88 assert(j->timer_watch.type == WATCH_JOB_TIMER);
89 assert(j->timer_watch.data.job == j);
90 assert(j->timer_watch.fd >= 0);
91
92 assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
93 close_nointr_nofail(j->timer_watch.fd);
94 }
95
a567261a 96 free(j->bus_client);
60918275
LP
97 free(j);
98}
a66d02c3 99
7527cb52 100JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts, Transaction *tr) {
e5b5ae50
LP
101 JobDependency *l;
102
103 assert(object);
104
105 /* Adds a new job link, which encodes that the 'subject' job
106 * needs the 'object' job in some way. If 'subject' is NULL
107 * this means the 'anchor' job (i.e. the one the user
35b8ca3a 108 * explicitly asked for) is the requester. */
e5b5ae50 109
ceed3570 110 if (!(l = new0(JobDependency, 1)))
e5b5ae50
LP
111 return NULL;
112
113 l->subject = subject;
114 l->object = object;
115 l->matters = matters;
69dd2852 116 l->conflicts = conflicts;
e5b5ae50 117
44d8db9e
LP
118 if (subject)
119 LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
120 else
7527cb52 121 LIST_PREPEND(JobDependency, subject, tr->anchor, l);
e5b5ae50 122
44d8db9e 123 LIST_PREPEND(JobDependency, object, object->object_list, l);
e5b5ae50
LP
124
125 return l;
126}
127
7527cb52 128void job_dependency_free(JobDependency *l, Transaction *tr) {
e5b5ae50
LP
129 assert(l);
130
44d8db9e
LP
131 if (l->subject)
132 LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
e5b5ae50 133 else
7527cb52 134 LIST_REMOVE(JobDependency, subject, tr->anchor, l);
e5b5ae50 135
44d8db9e 136 LIST_REMOVE(JobDependency, object, l->object->object_list, l);
e5b5ae50
LP
137
138 free(l);
139}
140
1ffba6fe 141void job_dump(Job *j, FILE*f, const char *prefix) {
a66d02c3
LP
142 assert(j);
143 assert(f);
144
9eb63b3c
LP
145 if (!prefix)
146 prefix = "";
147
ceed3570 148 fprintf(f,
40d50879
LP
149 "%s-> Job %u:\n"
150 "%s\tAction: %s -> %s\n"
5cb5a6ff
LP
151 "%s\tState: %s\n"
152 "%s\tForced: %s\n",
ceed3570 153 prefix, j->id,
ac155bb8 154 prefix, j->unit->id, job_type_to_string(j->type),
94f04347 155 prefix, job_state_to_string(j->state),
9e2f7c11 156 prefix, yes_no(j->override));
a66d02c3 157}
e5b5ae50
LP
158
159bool job_is_anchor(Job *j) {
160 JobDependency *l;
161
162 assert(j);
163
44d8db9e 164 LIST_FOREACH(object, l, j->object_list)
e5b5ae50
LP
165 if (!l->subject)
166 return true;
167
168 return false;
169}
1ffba6fe 170
348e27fe
MS
171/*
172 * Merging is commutative, so imagine the matrix as symmetric. We store only
173 * its lower triangle to avoid duplication. We don't store the main diagonal,
174 * because A merged with A is simply A.
175 *
176 * Merging is associative! A merged with B merged with C is the same as
177 * A merged with C merged with B.
178 *
179 * Mergeability is transitive! If A can be merged with B and B with C then
180 * A also with C.
181 *
182 * Also, if A merged with B cannot be merged with C, then either A or B cannot
183 * be merged with C either.
184 */
185static const JobType job_merging_table[] = {
186/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD JOB_RELOAD_OR_START JOB_RESTART JOB_TRY_RESTART */
187/************************************************************************************************************************************/
188/*JOB_START */
189/*JOB_VERIFY_ACTIVE */ JOB_START,
190/*JOB_STOP */ -1, -1,
191/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
192/*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START,
193/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART, JOB_RESTART,
194/*JOB_TRY_RESTART */ JOB_RESTART, JOB_TRY_RESTART, -1, JOB_TRY_RESTART, JOB_RESTART, JOB_RESTART,
195};
196
197JobType job_type_lookup_merge(JobType a, JobType b) {
198 assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2);
199 assert(a >= 0 && a < _JOB_TYPE_MAX);
200 assert(b >= 0 && b < _JOB_TYPE_MAX);
1ffba6fe
LP
201
202 if (a == b)
348e27fe 203 return a;
1ffba6fe 204
348e27fe
MS
205 if (a < b) {
206 JobType tmp = a;
207 a = b;
208 b = tmp;
1ffba6fe 209 }
e094e853 210
348e27fe 211 return job_merging_table[(a - 1) * a / 2 + b];
e094e853 212}
cd2dbd7d 213
593fbdd2
LP
214bool job_type_is_redundant(JobType a, UnitActiveState b) {
215 switch (a) {
216
217 case JOB_START:
218 return
219 b == UNIT_ACTIVE ||
032ff4af 220 b == UNIT_RELOADING;
593fbdd2
LP
221
222 case JOB_STOP:
223 return
6124958c 224 b == UNIT_INACTIVE ||
fdf20a31 225 b == UNIT_FAILED;
593fbdd2
LP
226
227 case JOB_VERIFY_ACTIVE:
228 return
229 b == UNIT_ACTIVE ||
032ff4af 230 b == UNIT_RELOADING;
593fbdd2
LP
231
232 case JOB_RELOAD:
233 return
032ff4af 234 b == UNIT_RELOADING;
593fbdd2
LP
235
236 case JOB_RELOAD_OR_START:
237 return
238 b == UNIT_ACTIVATING ||
032ff4af 239 b == UNIT_RELOADING;
593fbdd2
LP
240
241 case JOB_RESTART:
242 return
243 b == UNIT_ACTIVATING;
244
245 case JOB_TRY_RESTART:
246 return
247 b == UNIT_ACTIVATING;
248
249 default:
250 assert_not_reached("Invalid job type");
251 }
252}
253
5cb5a6ff 254bool job_is_runnable(Job *j) {
034c6ed7 255 Iterator i;
87f0e418 256 Unit *other;
5cb5a6ff
LP
257
258 assert(j);
ac1135be 259 assert(j->installed);
5cb5a6ff 260
87f0e418 261 /* Checks whether there is any job running for the units this
5cb5a6ff 262 * job needs to be running after (in the case of a 'positive'
e67c3609
LP
263 * job type) or before (in the case of a 'negative' job
264 * type. */
265
266 /* First check if there is an override */
cebe0d41 267 if (j->ignore_order)
e67c3609 268 return true;
5cb5a6ff
LP
269
270 if (j->type == JOB_START ||
271 j->type == JOB_VERIFY_ACTIVE ||
272 j->type == JOB_RELOAD ||
273 j->type == JOB_RELOAD_OR_START) {
274
275 /* Immediate result is that the job is or might be
276 * started. In this case lets wait for the
277 * dependencies, regardless whether they are
278 * starting or stopping something. */
279
ac155bb8
MS
280 SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
281 if (other->job)
5cb5a6ff
LP
282 return false;
283 }
284
285 /* Also, if something else is being stopped and we should
286 * change state after it, then lets wait. */
287
ac155bb8
MS
288 SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
289 if (other->job &&
290 (other->job->type == JOB_STOP ||
291 other->job->type == JOB_RESTART ||
292 other->job->type == JOB_TRY_RESTART))
5cb5a6ff
LP
293 return false;
294
295 /* This means that for a service a and a service b where b
296 * shall be started after a:
297 *
298 * start a + start b → 1st step start a, 2nd step start b
299 * start a + stop b → 1st step stop b, 2nd step start a
300 * stop a + start b → 1st step stop a, 2nd step start b
301 * stop a + stop b → 1st step stop b, 2nd step stop a
302 *
303 * This has the side effect that restarts are properly
304 * synchronized too. */
305
306 return true;
307}
308
bbd1a837
MS
309static void job_change_type(Job *j, JobType newtype) {
310 log_debug("Converting job %s/%s -> %s/%s",
311 j->unit->id, job_type_to_string(j->type),
312 j->unit->id, job_type_to_string(newtype));
313
314 j->type = newtype;
315}
316
5cb5a6ff
LP
317int job_run_and_invalidate(Job *j) {
318 int r;
2cf19a7a
LP
319 uint32_t id;
320 Manager *m;
ac1135be 321
5cb5a6ff 322 assert(j);
ac1135be 323 assert(j->installed);
5cb5a6ff 324
034c6ed7
LP
325 if (j->in_run_queue) {
326 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
327 j->in_run_queue = false;
328 }
5cb5a6ff
LP
329
330 if (j->state != JOB_WAITING)
331 return 0;
332
034c6ed7
LP
333 if (!job_is_runnable(j))
334 return -EAGAIN;
335
83c60c9f 336 j->state = JOB_RUNNING;
c1e1601e 337 job_add_to_dbus_queue(j);
83c60c9f 338
2cf19a7a
LP
339 /* While we execute this operation the job might go away (for
340 * example: because it is replaced by a new, conflicting
341 * job.) To make sure we don't access a freed job later on we
342 * store the id here, so that we can verify the job is still
343 * valid. */
344 id = j->id;
345 m = j->manager;
346
5cb5a6ff
LP
347 switch (j->type) {
348
dd17d388
MS
349 case JOB_RELOAD_OR_START:
350 if (unit_active_state(j->unit) == UNIT_ACTIVE) {
bbd1a837 351 job_change_type(j, JOB_RELOAD);
dd17d388
MS
352 r = unit_reload(j->unit);
353 break;
354 }
bbd1a837 355 job_change_type(j, JOB_START);
dd17d388
MS
356 /* fall through */
357
5cb5a6ff 358 case JOB_START:
87f0e418 359 r = unit_start(j->unit);
57339f47 360
dd17d388 361 /* If this unit cannot be started, then simply wait */
5cb5a6ff
LP
362 if (r == -EBADR)
363 r = 0;
364 break;
365
366 case JOB_VERIFY_ACTIVE: {
87f0e418
LP
367 UnitActiveState t = unit_active_state(j->unit);
368 if (UNIT_IS_ACTIVE_OR_RELOADING(t))
5cb5a6ff 369 r = -EALREADY;
87f0e418 370 else if (t == UNIT_ACTIVATING)
5cb5a6ff
LP
371 r = -EAGAIN;
372 else
373 r = -ENOEXEC;
374 break;
375 }
376
dd17d388
MS
377 case JOB_TRY_RESTART:
378 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) {
379 r = -ENOEXEC;
380 break;
381 }
bbd1a837 382 job_change_type(j, JOB_RESTART);
dd17d388
MS
383 /* fall through */
384
5cb5a6ff 385 case JOB_STOP:
dd17d388 386 case JOB_RESTART:
87f0e418 387 r = unit_stop(j->unit);
57339f47 388
dd17d388 389 /* If this unit cannot stopped, then simply wait. */
57339f47
LP
390 if (r == -EBADR)
391 r = 0;
5cb5a6ff
LP
392 break;
393
394 case JOB_RELOAD:
87f0e418 395 r = unit_reload(j->unit);
5cb5a6ff
LP
396 break;
397
5cb5a6ff 398 default:
44d8db9e 399 assert_not_reached("Unknown job type");
5cb5a6ff
LP
400 }
401
2cf19a7a
LP
402 if ((j = manager_get_job(m, id))) {
403 if (r == -EALREADY)
5d44db4a 404 r = job_finish_and_invalidate(j, JOB_DONE);
d68201e9
LP
405 else if (r == -ENOEXEC)
406 r = job_finish_and_invalidate(j, JOB_SKIPPED);
2cf19a7a
LP
407 else if (r == -EAGAIN)
408 j->state = JOB_WAITING;
409 else if (r < 0)
5d44db4a 410 r = job_finish_and_invalidate(j, JOB_FAILED);
2cf19a7a 411 }
5cb5a6ff
LP
412
413 return r;
414}
415
e02cd6f7
LP
416static void job_print_status_message(Unit *u, JobType t, JobResult result) {
417 assert(u);
418
419 if (t == JOB_START) {
420
421 switch (result) {
422
423 case JOB_DONE:
69120666
LP
424 if (u->condition_result)
425 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Started %s", unit_description(u));
e02cd6f7
LP
426 break;
427
428 case JOB_FAILED:
c1072ea0 429 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s", unit_description(u));
ac155bb8 430 unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
e02cd6f7
LP
431 break;
432
433 case JOB_DEPENDENCY:
c1072ea0 434 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s", unit_description(u));
e02cd6f7
LP
435 break;
436
437 case JOB_TIMEOUT:
c1072ea0 438 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s", unit_description(u));
e02cd6f7
LP
439 break;
440
441 default:
442 ;
443 }
444
445 } else if (t == JOB_STOP) {
446
447 switch (result) {
448
449 case JOB_TIMEOUT:
c1072ea0 450 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s", unit_description(u));
e02cd6f7
LP
451 break;
452
453 case JOB_DONE:
454 case JOB_FAILED:
5831e9b7 455 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Stopped %s", unit_description(u));
e02cd6f7
LP
456 break;
457
458 default:
459 ;
460 }
461 }
462}
463
5d44db4a 464int job_finish_and_invalidate(Job *j, JobResult result) {
87f0e418
LP
465 Unit *u;
466 Unit *other;
b866264a 467 JobType t;
034c6ed7 468 Iterator i;
563ba9ea 469 bool recursed = false;
5cb5a6ff
LP
470
471 assert(j);
ac1135be 472 assert(j->installed);
5cb5a6ff 473
c1e1601e 474 job_add_to_dbus_queue(j);
f50e0a01 475
034c6ed7 476 /* Patch restart jobs so that they become normal start jobs */
dd17d388 477 if (result == JOB_DONE && j->type == JOB_RESTART) {
f50e0a01 478
bbd1a837 479 job_change_type(j, JOB_START);
9c2d9caa 480 j->state = JOB_WAITING;
cc42e081
LP
481
482 job_add_to_run_queue(j);
57981b98
LP
483
484 u = j->unit;
485 goto finish;
5cb5a6ff
LP
486 }
487
5d44db4a 488 j->result = result;
76bf48b7 489
ac155bb8 490 log_debug("Job %s/%s finished, result=%s", j->unit->id, job_type_to_string(j->type), job_result_to_string(result));
9c2d9caa 491
5d44db4a 492 if (result == JOB_FAILED)
76bf48b7
LP
493 j->manager->n_failed_jobs ++;
494
87f0e418 495 u = j->unit;
5cb5a6ff 496 t = j->type;
97e7d748 497 job_uninstall(j);
5cb5a6ff
LP
498 job_free(j);
499
e02cd6f7 500 job_print_status_message(u, t, result);
9e58ff9c 501
5cb5a6ff 502 /* Fail depending jobs on failure */
5d44db4a 503 if (result != JOB_DONE) {
5cb5a6ff
LP
504
505 if (t == JOB_START ||
506 t == JOB_VERIFY_ACTIVE ||
507 t == JOB_RELOAD_OR_START) {
508
ac155bb8
MS
509 SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
510 if (other->job &&
511 (other->job->type == JOB_START ||
512 other->job->type == JOB_VERIFY_ACTIVE ||
513 other->job->type == JOB_RELOAD_OR_START)) {
514 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
515 recursed = true;
516 }
5cb5a6ff 517
ac155bb8
MS
518 SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
519 if (other->job &&
520 (other->job->type == JOB_START ||
521 other->job->type == JOB_VERIFY_ACTIVE ||
522 other->job->type == JOB_RELOAD_OR_START)) {
523 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
524 recursed = true;
525 }
e6a3ff95 526
ac155bb8
MS
527 SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
528 if (other->job &&
529 !other->job->override &&
530 (other->job->type == JOB_START ||
531 other->job->type == JOB_VERIFY_ACTIVE ||
532 other->job->type == JOB_RELOAD_OR_START)) {
533 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
534 recursed = true;
535 }
5cb5a6ff
LP
536
537 } else if (t == JOB_STOP) {
538
ac155bb8
MS
539 SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
540 if (other->job &&
541 (other->job->type == JOB_START ||
542 other->job->type == JOB_VERIFY_ACTIVE ||
543 other->job->type == JOB_RELOAD_OR_START)) {
544 job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
563ba9ea
MS
545 recursed = true;
546 }
5cb5a6ff
LP
547 }
548 }
549
c0daa706
LP
550 /* Trigger OnFailure dependencies that are not generated by
551 * the unit itself. We don't tread JOB_CANCELED as failure in
552 * this context. And JOB_FAILURE is already handled by the
553 * unit itself. */
222ae6a8
LP
554 if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
555 log_notice("Job %s/%s failed with result '%s'.",
ac155bb8 556 u->id,
222ae6a8
LP
557 job_type_to_string(t),
558 job_result_to_string(result));
559
c0daa706 560 unit_trigger_on_failure(u);
222ae6a8 561 }
c0daa706 562
57981b98 563finish:
5cb5a6ff 564 /* Try to start the next jobs that can be started */
ac155bb8
MS
565 SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
566 if (other->job)
567 job_add_to_run_queue(other->job);
568 SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
569 if (other->job)
570 job_add_to_run_queue(other->job);
5cb5a6ff 571
ac155bb8 572 manager_check_finished(u->manager);
b0c918b9 573
563ba9ea 574 return recursed;
5cb5a6ff 575}
034c6ed7 576
faf919f1
LP
577int job_start_timer(Job *j) {
578 struct itimerspec its;
579 struct epoll_event ev;
580 int fd, r;
581 assert(j);
582
ac155bb8 583 if (j->unit->job_timeout <= 0 ||
faf919f1
LP
584 j->timer_watch.type == WATCH_JOB_TIMER)
585 return 0;
586
587 assert(j->timer_watch.type == WATCH_INVALID);
588
589 if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
590 r = -errno;
591 goto fail;
592 }
593
594 zero(its);
ac155bb8 595 timespec_store(&its.it_value, j->unit->job_timeout);
faf919f1
LP
596
597 if (timerfd_settime(fd, 0, &its, NULL) < 0) {
598 r = -errno;
599 goto fail;
600 }
601
602 zero(ev);
603 ev.data.ptr = &j->timer_watch;
604 ev.events = EPOLLIN;
605
606 if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
607 r = -errno;
608 goto fail;
609 }
610
611 j->timer_watch.type = WATCH_JOB_TIMER;
612 j->timer_watch.fd = fd;
613 j->timer_watch.data.job = j;
614
615 return 0;
616
617fail:
618 if (fd >= 0)
619 close_nointr_nofail(fd);
620
621 return r;
622}
623
c1e1601e 624void job_add_to_run_queue(Job *j) {
034c6ed7 625 assert(j);
ac1135be 626 assert(j->installed);
034c6ed7
LP
627
628 if (j->in_run_queue)
629 return;
630
631 LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
632 j->in_run_queue = true;
633}
94f04347 634
c1e1601e
LP
635void job_add_to_dbus_queue(Job *j) {
636 assert(j);
637 assert(j->installed);
638
639 if (j->in_dbus_queue)
640 return;
641
a567261a
LP
642 /* We don't check if anybody is subscribed here, since this
643 * job might just have been created and not yet assigned to a
644 * connection/client. */
94b6dfa2 645
c1e1601e
LP
646 LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
647 j->in_dbus_queue = true;
648}
649
ea430986
LP
650char *job_dbus_path(Job *j) {
651 char *p;
652
653 assert(j);
654
655 if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
656 return NULL;
657
658 return p;
659}
660
faf919f1
LP
661void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
662 assert(j);
663 assert(w == &j->timer_watch);
664
ac155bb8 665 log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
5d44db4a 666 job_finish_and_invalidate(j, JOB_TIMEOUT);
faf919f1
LP
667}
668
94f04347
LP
669static const char* const job_state_table[_JOB_STATE_MAX] = {
670 [JOB_WAITING] = "waiting",
671 [JOB_RUNNING] = "running"
672};
673
674DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
675
676static const char* const job_type_table[_JOB_TYPE_MAX] = {
677 [JOB_START] = "start",
678 [JOB_VERIFY_ACTIVE] = "verify-active",
679 [JOB_STOP] = "stop",
680 [JOB_RELOAD] = "reload",
681 [JOB_RELOAD_OR_START] = "reload-or-start",
682 [JOB_RESTART] = "restart",
683 [JOB_TRY_RESTART] = "try-restart",
684};
685
686DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
b548631a
LP
687
688static const char* const job_mode_table[_JOB_MODE_MAX] = {
689 [JOB_FAIL] = "fail",
c497c7a9 690 [JOB_REPLACE] = "replace",
e67c3609 691 [JOB_ISOLATE] = "isolate",
cebe0d41
LP
692 [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
693 [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
b548631a
LP
694};
695
696DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
5d44db4a
LP
697
698static const char* const job_result_table[_JOB_RESULT_MAX] = {
699 [JOB_DONE] = "done",
700 [JOB_CANCELED] = "canceled",
701 [JOB_TIMEOUT] = "timeout",
702 [JOB_FAILED] = "failed",
d68201e9
LP
703 [JOB_DEPENDENCY] = "dependency",
704 [JOB_SKIPPED] = "skipped"
5d44db4a
LP
705};
706
707DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);