chiark / gitweb /
b21de44c142e54c761647aa3626ef0e1b5a65f9a
[elogind.git] / src / core / job.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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
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.
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
16   Lesser General Public License for more details.
17
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/>.
20 ***/
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <sys/timerfd.h>
25 #include <sys/epoll.h>
26
27 #include "set.h"
28 #include "unit.h"
29 #include "macro.h"
30 #include "strv.h"
31 #include "load-fragment.h"
32 #include "load-dropin.h"
33 #include "log.h"
34 #include "dbus-job.h"
35
36 JobBusClient* 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
50 Job* job_new(Unit *unit, JobType type) {
51         Job *j;
52
53         assert(type < _JOB_TYPE_MAX);
54         assert(unit);
55
56         if (!(j = new0(Job, 1)))
57                 return NULL;
58
59         j->manager = unit->manager;
60         j->id = j->manager->current_job_id++;
61         j->type = type;
62         j->unit = unit;
63
64         j->timer_watch.type = WATCH_INVALID;
65
66         /* We don't link it here, that's what job_dependency() is for */
67
68         return j;
69 }
70
71 void job_free(Job *j) {
72         JobBusClient *cl;
73
74         assert(j);
75         assert(!j->installed);
76         assert(!j->transaction_prev);
77         assert(!j->transaction_next);
78         assert(!j->subject_list);
79         assert(!j->object_list);
80
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
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
96         while ((cl = j->bus_client_list)) {
97                 LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
98                 free(cl);
99         }
100         free(j);
101 }
102
103 void job_uninstall(Job *j) {
104         assert(j->installed);
105         assert(j->unit->job == j);
106         /* Detach from next 'bigger' objects */
107
108         bus_job_send_removed_signal(j);
109
110         j->unit->job = NULL;
111         unit_add_to_gc_queue(j->unit);
112
113         hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
114         j->installed = false;
115 }
116
117 static bool job_type_allows_late_merge(JobType t) {
118         /* Tells whether it is OK to merge a job of type 't' with an already
119          * running job.
120          * Reloads cannot be merged this way. Think of the sequence:
121          * 1. Reload of a daemon is in progress; the daemon has already loaded
122          *    its config file, but hasn't completed the reload operation yet.
123          * 2. Edit foo's config file.
124          * 3. Trigger another reload to have the daemon use the new config.
125          * Should the second reload job be merged into the first one, the daemon
126          * would not know about the new config.
127          * JOB_RESTART jobs on the other hand can be merged, because they get
128          * patched into JOB_START after stopping the unit. So if we see a
129          * JOB_RESTART running, it means the unit hasn't stopped yet and at
130          * this time the merge is still allowed. */
131         return !(t == JOB_RELOAD || t == JOB_RELOAD_OR_START);
132 }
133
134 static void job_merge_into_installed(Job *j, Job *other) {
135         assert(j->installed);
136         assert(j->unit == other->unit);
137
138         j->type = job_type_lookup_merge(j->type, other->type);
139         assert(j->type >= 0);
140
141         j->override = j->override || other->override;
142 }
143
144 Job* job_install(Job *j) {
145         Job *uj = j->unit->job;
146
147         assert(!j->installed);
148
149         if (uj) {
150                 if (job_type_is_conflicting(uj->type, j->type))
151                         job_finish_and_invalidate(uj, JOB_CANCELED);
152                 else {
153                         /* not conflicting, i.e. mergeable */
154
155                         if (uj->state == JOB_WAITING ||
156                             (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
157                                 job_merge_into_installed(uj, j);
158                                 log_debug("Merged into installed job %s/%s as %u",
159                                           uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
160                                 return uj;
161                         } else {
162                                 /* already running and not safe to merge into */
163                                 /* Patch uj to become a merged job and re-run it. */
164                                 /* XXX It should be safer to queue j to run after uj finishes, but it is
165                                  * not currently possible to have more than one installed job per unit. */
166                                 job_merge_into_installed(uj, j);
167                                 log_debug("Merged into running job, re-running: %s/%s as %u",
168                                           uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
169                                 uj->state = JOB_WAITING;
170                                 return uj;
171                         }
172                 }
173         }
174
175         /* Install the job */
176         j->unit->job = j;
177         j->installed = true;
178         j->manager->n_installed_jobs ++;
179         log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
180         return j;
181 }
182
183 JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
184         JobDependency *l;
185
186         assert(object);
187
188         /* Adds a new job link, which encodes that the 'subject' job
189          * needs the 'object' job in some way. If 'subject' is NULL
190          * this means the 'anchor' job (i.e. the one the user
191          * explicitly asked for) is the requester. */
192
193         if (!(l = new0(JobDependency, 1)))
194                 return NULL;
195
196         l->subject = subject;
197         l->object = object;
198         l->matters = matters;
199         l->conflicts = conflicts;
200
201         if (subject)
202                 LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
203
204         LIST_PREPEND(JobDependency, object, object->object_list, l);
205
206         return l;
207 }
208
209 void job_dependency_free(JobDependency *l) {
210         assert(l);
211
212         if (l->subject)
213                 LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
214
215         LIST_REMOVE(JobDependency, object, l->object->object_list, l);
216
217         free(l);
218 }
219
220 void job_dump(Job *j, FILE*f, const char *prefix) {
221         assert(j);
222         assert(f);
223
224         if (!prefix)
225                 prefix = "";
226
227         fprintf(f,
228                 "%s-> Job %u:\n"
229                 "%s\tAction: %s -> %s\n"
230                 "%s\tState: %s\n"
231                 "%s\tForced: %s\n",
232                 prefix, j->id,
233                 prefix, j->unit->id, job_type_to_string(j->type),
234                 prefix, job_state_to_string(j->state),
235                 prefix, yes_no(j->override));
236 }
237
238 /*
239  * Merging is commutative, so imagine the matrix as symmetric. We store only
240  * its lower triangle to avoid duplication. We don't store the main diagonal,
241  * because A merged with A is simply A.
242  *
243  * Merging is associative! A merged with B merged with C is the same as
244  * A merged with C merged with B.
245  *
246  * Mergeability is transitive! If A can be merged with B and B with C then
247  * A also with C.
248  *
249  * Also, if A merged with B cannot be merged with C, then either A or B cannot
250  * be merged with C either.
251  */
252 static const JobType job_merging_table[] = {
253 /* What \ With       *  JOB_START         JOB_VERIFY_ACTIVE  JOB_STOP JOB_RELOAD   JOB_RELOAD_OR_START  JOB_RESTART JOB_TRY_RESTART */
254 /************************************************************************************************************************************/
255 /*JOB_START          */
256 /*JOB_VERIFY_ACTIVE  */ JOB_START,
257 /*JOB_STOP           */ -1,                  -1,
258 /*JOB_RELOAD         */ JOB_RELOAD_OR_START, JOB_RELOAD,          -1,
259 /*JOB_RELOAD_OR_START*/ JOB_RELOAD_OR_START, JOB_RELOAD_OR_START, -1, JOB_RELOAD_OR_START,
260 /*JOB_RESTART        */ JOB_RESTART,         JOB_RESTART,         -1, JOB_RESTART,         JOB_RESTART,
261 /*JOB_TRY_RESTART    */ JOB_RESTART,         JOB_TRY_RESTART,     -1, JOB_TRY_RESTART,     JOB_RESTART, JOB_RESTART,
262 };
263
264 JobType job_type_lookup_merge(JobType a, JobType b) {
265         assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX * (_JOB_TYPE_MAX - 1) / 2);
266         assert(a >= 0 && a < _JOB_TYPE_MAX);
267         assert(b >= 0 && b < _JOB_TYPE_MAX);
268
269         if (a == b)
270                 return a;
271
272         if (a < b) {
273                 JobType tmp = a;
274                 a = b;
275                 b = tmp;
276         }
277
278         return job_merging_table[(a - 1) * a / 2 + b];
279 }
280
281 bool job_type_is_redundant(JobType a, UnitActiveState b) {
282         switch (a) {
283
284         case JOB_START:
285                 return
286                         b == UNIT_ACTIVE ||
287                         b == UNIT_RELOADING;
288
289         case JOB_STOP:
290                 return
291                         b == UNIT_INACTIVE ||
292                         b == UNIT_FAILED;
293
294         case JOB_VERIFY_ACTIVE:
295                 return
296                         b == UNIT_ACTIVE ||
297                         b == UNIT_RELOADING;
298
299         case JOB_RELOAD:
300                 return
301                         b == UNIT_RELOADING;
302
303         case JOB_RELOAD_OR_START:
304                 return
305                         b == UNIT_ACTIVATING ||
306                         b == UNIT_RELOADING;
307
308         case JOB_RESTART:
309                 return
310                         b == UNIT_ACTIVATING;
311
312         case JOB_TRY_RESTART:
313                 return
314                         b == UNIT_ACTIVATING;
315
316         default:
317                 assert_not_reached("Invalid job type");
318         }
319 }
320
321 bool job_is_runnable(Job *j) {
322         Iterator i;
323         Unit *other;
324
325         assert(j);
326         assert(j->installed);
327
328         /* Checks whether there is any job running for the units this
329          * job needs to be running after (in the case of a 'positive'
330          * job type) or before (in the case of a 'negative' job
331          * type. */
332
333         /* First check if there is an override */
334         if (j->ignore_order)
335                 return true;
336
337         if (j->type == JOB_START ||
338             j->type == JOB_VERIFY_ACTIVE ||
339             j->type == JOB_RELOAD ||
340             j->type == JOB_RELOAD_OR_START) {
341
342                 /* Immediate result is that the job is or might be
343                  * started. In this case lets wait for the
344                  * dependencies, regardless whether they are
345                  * starting or stopping something. */
346
347                 SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
348                         if (other->job)
349                                 return false;
350         }
351
352         /* Also, if something else is being stopped and we should
353          * change state after it, then lets wait. */
354
355         SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
356                 if (other->job &&
357                     (other->job->type == JOB_STOP ||
358                      other->job->type == JOB_RESTART ||
359                      other->job->type == JOB_TRY_RESTART))
360                         return false;
361
362         /* This means that for a service a and a service b where b
363          * shall be started after a:
364          *
365          *  start a + start b → 1st step start a, 2nd step start b
366          *  start a + stop b  → 1st step stop b,  2nd step start a
367          *  stop a  + start b → 1st step stop a,  2nd step start b
368          *  stop a  + stop b  → 1st step stop b,  2nd step stop a
369          *
370          *  This has the side effect that restarts are properly
371          *  synchronized too. */
372
373         return true;
374 }
375
376 static void job_change_type(Job *j, JobType newtype) {
377         log_debug("Converting job %s/%s -> %s/%s",
378                   j->unit->id, job_type_to_string(j->type),
379                   j->unit->id, job_type_to_string(newtype));
380
381         j->type = newtype;
382 }
383
384 int job_run_and_invalidate(Job *j) {
385         int r;
386         uint32_t id;
387         Manager *m;
388
389         assert(j);
390         assert(j->installed);
391
392         if (j->in_run_queue) {
393                 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
394                 j->in_run_queue = false;
395         }
396
397         if (j->state != JOB_WAITING)
398                 return 0;
399
400         if (!job_is_runnable(j))
401                 return -EAGAIN;
402
403         j->state = JOB_RUNNING;
404         job_add_to_dbus_queue(j);
405
406         /* While we execute this operation the job might go away (for
407          * example: because it is replaced by a new, conflicting
408          * job.) To make sure we don't access a freed job later on we
409          * store the id here, so that we can verify the job is still
410          * valid. */
411         id = j->id;
412         m = j->manager;
413
414         switch (j->type) {
415
416                 case JOB_RELOAD_OR_START:
417                         if (unit_active_state(j->unit) == UNIT_ACTIVE) {
418                                 job_change_type(j, JOB_RELOAD);
419                                 r = unit_reload(j->unit);
420                                 break;
421                         }
422                         job_change_type(j, JOB_START);
423                         /* fall through */
424
425                 case JOB_START:
426                         r = unit_start(j->unit);
427
428                         /* If this unit cannot be started, then simply wait */
429                         if (r == -EBADR)
430                                 r = 0;
431                         break;
432
433                 case JOB_VERIFY_ACTIVE: {
434                         UnitActiveState t = unit_active_state(j->unit);
435                         if (UNIT_IS_ACTIVE_OR_RELOADING(t))
436                                 r = -EALREADY;
437                         else if (t == UNIT_ACTIVATING)
438                                 r = -EAGAIN;
439                         else
440                                 r = -ENOEXEC;
441                         break;
442                 }
443
444                 case JOB_TRY_RESTART:
445                         if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(j->unit))) {
446                                 r = -ENOEXEC;
447                                 break;
448                         }
449                         job_change_type(j, JOB_RESTART);
450                         /* fall through */
451
452                 case JOB_STOP:
453                 case JOB_RESTART:
454                         r = unit_stop(j->unit);
455
456                         /* If this unit cannot stopped, then simply wait. */
457                         if (r == -EBADR)
458                                 r = 0;
459                         break;
460
461                 case JOB_RELOAD:
462                         r = unit_reload(j->unit);
463                         break;
464
465                 default:
466                         assert_not_reached("Unknown job type");
467         }
468
469         if ((j = manager_get_job(m, id))) {
470                 if (r == -EALREADY)
471                         r = job_finish_and_invalidate(j, JOB_DONE);
472                 else if (r == -ENOEXEC)
473                         r = job_finish_and_invalidate(j, JOB_SKIPPED);
474                 else if (r == -EAGAIN)
475                         j->state = JOB_WAITING;
476                 else if (r < 0)
477                         r = job_finish_and_invalidate(j, JOB_FAILED);
478         }
479
480         return r;
481 }
482
483 static void job_print_status_message(Unit *u, JobType t, JobResult result) {
484         assert(u);
485
486         if (t == JOB_START) {
487
488                 switch (result) {
489
490                 case JOB_DONE:
491                         if (u->condition_result)
492                                 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Started %s", unit_description(u));
493                         break;
494
495                 case JOB_FAILED:
496                         unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s", unit_description(u));
497                         unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
498                         break;
499
500                 case JOB_DEPENDENCY:
501                         unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s", unit_description(u));
502                         break;
503
504                 case JOB_TIMEOUT:
505                         unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s", unit_description(u));
506                         break;
507
508                 default:
509                         ;
510                 }
511
512         } else if (t == JOB_STOP) {
513
514                 switch (result) {
515
516                 case JOB_TIMEOUT:
517                         unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s", unit_description(u));
518                         break;
519
520                 case JOB_DONE:
521                 case JOB_FAILED:
522                         unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, "Stopped %s", unit_description(u));
523                         break;
524
525                 default:
526                         ;
527                 }
528         }
529 }
530
531 int job_finish_and_invalidate(Job *j, JobResult result) {
532         Unit *u;
533         Unit *other;
534         JobType t;
535         Iterator i;
536         bool recursed = false;
537
538         assert(j);
539         assert(j->installed);
540
541         job_add_to_dbus_queue(j);
542
543         /* Patch restart jobs so that they become normal start jobs */
544         if (result == JOB_DONE && j->type == JOB_RESTART) {
545
546                 job_change_type(j, JOB_START);
547                 j->state = JOB_WAITING;
548
549                 job_add_to_run_queue(j);
550
551                 u = j->unit;
552                 goto finish;
553         }
554
555         j->result = result;
556
557         log_debug("Job %s/%s finished, result=%s", j->unit->id, job_type_to_string(j->type), job_result_to_string(result));
558
559         if (result == JOB_FAILED)
560                 j->manager->n_failed_jobs ++;
561
562         u = j->unit;
563         t = j->type;
564         job_uninstall(j);
565         job_free(j);
566
567         job_print_status_message(u, t, result);
568
569         /* Fail depending jobs on failure */
570         if (result != JOB_DONE) {
571
572                 if (t == JOB_START ||
573                     t == JOB_VERIFY_ACTIVE ||
574                     t == JOB_RELOAD_OR_START) {
575
576                         SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
577                                 if (other->job &&
578                                     (other->job->type == JOB_START ||
579                                      other->job->type == JOB_VERIFY_ACTIVE ||
580                                      other->job->type == JOB_RELOAD_OR_START)) {
581                                         job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
582                                         recursed = true;
583                                 }
584
585                         SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
586                                 if (other->job &&
587                                     (other->job->type == JOB_START ||
588                                      other->job->type == JOB_VERIFY_ACTIVE ||
589                                      other->job->type == JOB_RELOAD_OR_START)) {
590                                         job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
591                                         recursed = true;
592                                 }
593
594                         SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
595                                 if (other->job &&
596                                     !other->job->override &&
597                                     (other->job->type == JOB_START ||
598                                      other->job->type == JOB_VERIFY_ACTIVE ||
599                                      other->job->type == JOB_RELOAD_OR_START)) {
600                                         job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
601                                         recursed = true;
602                                 }
603
604                 } else if (t == JOB_STOP) {
605
606                         SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
607                                 if (other->job &&
608                                     (other->job->type == JOB_START ||
609                                      other->job->type == JOB_VERIFY_ACTIVE ||
610                                      other->job->type == JOB_RELOAD_OR_START)) {
611                                         job_finish_and_invalidate(other->job, JOB_DEPENDENCY);
612                                         recursed = true;
613                                 }
614                 }
615         }
616
617         /* Trigger OnFailure dependencies that are not generated by
618          * the unit itself. We don't tread JOB_CANCELED as failure in
619          * this context. And JOB_FAILURE is already handled by the
620          * unit itself. */
621         if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
622                 log_notice("Job %s/%s failed with result '%s'.",
623                            u->id,
624                            job_type_to_string(t),
625                            job_result_to_string(result));
626
627                 unit_trigger_on_failure(u);
628         }
629
630 finish:
631         /* Try to start the next jobs that can be started */
632         SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
633                 if (other->job)
634                         job_add_to_run_queue(other->job);
635         SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
636                 if (other->job)
637                         job_add_to_run_queue(other->job);
638
639         manager_check_finished(u->manager);
640
641         return recursed;
642 }
643
644 int job_start_timer(Job *j) {
645         struct itimerspec its;
646         struct epoll_event ev;
647         int fd, r;
648         assert(j);
649
650         if (j->unit->job_timeout <= 0 ||
651             j->timer_watch.type == WATCH_JOB_TIMER)
652                 return 0;
653
654         assert(j->timer_watch.type == WATCH_INVALID);
655
656         if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
657                 r = -errno;
658                 goto fail;
659         }
660
661         zero(its);
662         timespec_store(&its.it_value, j->unit->job_timeout);
663
664         if (timerfd_settime(fd, 0, &its, NULL) < 0) {
665                 r = -errno;
666                 goto fail;
667         }
668
669         zero(ev);
670         ev.data.ptr = &j->timer_watch;
671         ev.events = EPOLLIN;
672
673         if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
674                 r = -errno;
675                 goto fail;
676         }
677
678         j->timer_watch.type = WATCH_JOB_TIMER;
679         j->timer_watch.fd = fd;
680         j->timer_watch.data.job = j;
681
682         return 0;
683
684 fail:
685         if (fd >= 0)
686                 close_nointr_nofail(fd);
687
688         return r;
689 }
690
691 void job_add_to_run_queue(Job *j) {
692         assert(j);
693         assert(j->installed);
694
695         if (j->in_run_queue)
696                 return;
697
698         LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
699         j->in_run_queue = true;
700 }
701
702 void job_add_to_dbus_queue(Job *j) {
703         assert(j);
704         assert(j->installed);
705
706         if (j->in_dbus_queue)
707                 return;
708
709         /* We don't check if anybody is subscribed here, since this
710          * job might just have been created and not yet assigned to a
711          * connection/client. */
712
713         LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
714         j->in_dbus_queue = true;
715 }
716
717 char *job_dbus_path(Job *j) {
718         char *p;
719
720         assert(j);
721
722         if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
723                 return NULL;
724
725         return p;
726 }
727
728 void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
729         assert(j);
730         assert(w == &j->timer_watch);
731
732         log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
733         job_finish_and_invalidate(j, JOB_TIMEOUT);
734 }
735
736 static const char* const job_state_table[_JOB_STATE_MAX] = {
737         [JOB_WAITING] = "waiting",
738         [JOB_RUNNING] = "running"
739 };
740
741 DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
742
743 static const char* const job_type_table[_JOB_TYPE_MAX] = {
744         [JOB_START] = "start",
745         [JOB_VERIFY_ACTIVE] = "verify-active",
746         [JOB_STOP] = "stop",
747         [JOB_RELOAD] = "reload",
748         [JOB_RELOAD_OR_START] = "reload-or-start",
749         [JOB_RESTART] = "restart",
750         [JOB_TRY_RESTART] = "try-restart",
751 };
752
753 DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
754
755 static const char* const job_mode_table[_JOB_MODE_MAX] = {
756         [JOB_FAIL] = "fail",
757         [JOB_REPLACE] = "replace",
758         [JOB_ISOLATE] = "isolate",
759         [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
760         [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
761 };
762
763 DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
764
765 static const char* const job_result_table[_JOB_RESULT_MAX] = {
766         [JOB_DONE] = "done",
767         [JOB_CANCELED] = "canceled",
768         [JOB_TIMEOUT] = "timeout",
769         [JOB_FAILED] = "failed",
770         [JOB_DEPENDENCY] = "dependency",
771         [JOB_SKIPPED] = "skipped"
772 };
773
774 DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);