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>
27 #include "systemd/sd-id128.h"
28 #include "systemd/sd-messages.h"
33 #include "load-fragment.h"
34 #include "load-dropin.h"
38 JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) {
42 name_len = strlen(name);
43 cl = malloc0(sizeof(JobBusClient) + name_len + 1);
48 memcpy(cl->name, name, name_len + 1);
52 Job* job_new_raw(Unit *unit) {
55 /* used for deserialization */
63 j->manager = unit->manager;
65 j->type = _JOB_TYPE_INVALID;
66 j->timer_watch.type = WATCH_INVALID;
71 Job* job_new(Unit *unit, JobType type) {
74 assert(type < _JOB_TYPE_MAX);
76 j = job_new_raw(unit);
80 j->id = j->manager->current_job_id++;
83 /* We don't link it here, that's what job_dependency() is for */
88 void job_free(Job *j) {
92 assert(!j->installed);
93 assert(!j->transaction_prev);
94 assert(!j->transaction_next);
95 assert(!j->subject_list);
96 assert(!j->object_list);
99 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
101 if (j->in_dbus_queue)
102 LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
104 if (j->timer_watch.type != WATCH_INVALID) {
105 assert(j->timer_watch.type == WATCH_JOB_TIMER);
106 assert(j->timer_watch.data.job == j);
107 assert(j->timer_watch.fd >= 0);
109 assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
110 close_nointr_nofail(j->timer_watch.fd);
113 while ((cl = j->bus_client_list)) {
114 LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
120 void job_uninstall(Job *j) {
123 assert(j->installed);
125 pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
128 /* Detach from next 'bigger' objects */
130 /* daemon-reload should be transparent to job observers */
131 if (j->manager->n_reloading <= 0)
132 bus_job_send_removed_signal(j);
136 unit_add_to_gc_queue(j->unit);
138 hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
139 j->installed = false;
142 static bool job_type_allows_late_merge(JobType t) {
143 /* Tells whether it is OK to merge a job of type 't' with an already
145 * Reloads cannot be merged this way. Think of the sequence:
146 * 1. Reload of a daemon is in progress; the daemon has already loaded
147 * its config file, but hasn't completed the reload operation yet.
148 * 2. Edit foo's config file.
149 * 3. Trigger another reload to have the daemon use the new config.
150 * Should the second reload job be merged into the first one, the daemon
151 * would not know about the new config.
152 * JOB_RESTART jobs on the other hand can be merged, because they get
153 * patched into JOB_START after stopping the unit. So if we see a
154 * JOB_RESTART running, it means the unit hasn't stopped yet and at
155 * this time the merge is still allowed. */
156 return t != JOB_RELOAD;
159 static void job_merge_into_installed(Job *j, Job *other) {
160 assert(j->installed);
161 assert(j->unit == other->unit);
163 if (j->type != JOB_NOP)
164 job_type_merge_and_collapse(&j->type, other->type, j->unit);
166 assert(other->type == JOB_NOP);
168 j->override = j->override || other->override;
169 j->ignore_order = j->ignore_order || other->ignore_order;
172 Job* job_install(Job *j) {
176 assert(!j->installed);
177 assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
179 pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
183 if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
184 job_finish_and_invalidate(uj, JOB_CANCELED, false);
186 /* not conflicting, i.e. mergeable */
188 if (j->type == JOB_NOP || uj->state == JOB_WAITING ||
189 (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
190 job_merge_into_installed(uj, j);
191 log_debug_unit(uj->unit->id,
192 "Merged into installed job %s/%s as %u",
193 uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
196 /* already running and not safe to merge into */
197 /* Patch uj to become a merged job and re-run it. */
198 /* XXX It should be safer to queue j to run after uj finishes, but it is
199 * not currently possible to have more than one installed job per unit. */
200 job_merge_into_installed(uj, j);
201 log_debug_unit(uj->unit->id,
202 "Merged into running job, re-running: %s/%s as %u",
203 uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
204 uj->state = JOB_WAITING;
210 /* Install the job */
213 j->manager->n_installed_jobs ++;
214 log_debug_unit(j->unit->id,
215 "Installed new job %s/%s as %u",
216 j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
220 int job_install_deserialized(Job *j) {
223 assert(!j->installed);
225 if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
226 log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
230 pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
233 log_debug_unit(j->unit->id,
234 "Unit %s already has a job installed. Not installing deserialized job.",
240 log_debug_unit(j->unit->id,
241 "Reinstalled deserialized job %s/%s as %u",
242 j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
246 JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
251 /* Adds a new job link, which encodes that the 'subject' job
252 * needs the 'object' job in some way. If 'subject' is NULL
253 * this means the 'anchor' job (i.e. the one the user
254 * explicitly asked for) is the requester. */
256 if (!(l = new0(JobDependency, 1)))
259 l->subject = subject;
261 l->matters = matters;
262 l->conflicts = conflicts;
265 LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
267 LIST_PREPEND(JobDependency, object, object->object_list, l);
272 void job_dependency_free(JobDependency *l) {
276 LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
278 LIST_REMOVE(JobDependency, object, l->object->object_list, l);
283 void job_dump(Job *j, FILE*f, const char *prefix) {
292 "%s\tAction: %s -> %s\n"
296 prefix, j->unit->id, job_type_to_string(j->type),
297 prefix, job_state_to_string(j->state),
298 prefix, yes_no(j->override));
302 * Merging is commutative, so imagine the matrix as symmetric. We store only
303 * its lower triangle to avoid duplication. We don't store the main diagonal,
304 * because A merged with A is simply A.
306 * If the resulting type is collapsed immediately afterwards (to get rid of
307 * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
308 * the following properties hold:
310 * Merging is associative! A merged with B merged with C is the same as
311 * A merged with C merged with B.
313 * Mergeability is transitive! If A can be merged with B and B with C then
316 * Also, if A merged with B cannot be merged with C, then either A or B cannot
317 * be merged with C either.
319 static const JobType job_merging_table[] = {
320 /* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */
321 /*********************************************************************************/
323 /*JOB_VERIFY_ACTIVE */ JOB_START,
324 /*JOB_STOP */ -1, -1,
325 /*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
326 /*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART,
329 JobType job_type_lookup_merge(JobType a, JobType b) {
330 assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
331 assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
332 assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
343 return job_merging_table[(a - 1) * a / 2 + b];
346 bool job_type_is_redundant(JobType a, UnitActiveState b) {
356 b == UNIT_INACTIVE ||
359 case JOB_VERIFY_ACTIVE:
370 b == UNIT_ACTIVATING;
373 assert_not_reached("Invalid job type");
377 void job_type_collapse(JobType *t, Unit *u) {
382 case JOB_TRY_RESTART:
383 s = unit_active_state(u);
384 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
390 case JOB_RELOAD_OR_START:
391 s = unit_active_state(u);
392 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
403 int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
404 JobType t = job_type_lookup_merge(*a, b);
408 job_type_collapse(a, u);
412 bool job_is_runnable(Job *j) {
417 assert(j->installed);
419 /* Checks whether there is any job running for the units this
420 * job needs to be running after (in the case of a 'positive'
421 * job type) or before (in the case of a 'negative' job
424 /* First check if there is an override */
428 if (j->type == JOB_NOP)
431 if (j->type == JOB_START ||
432 j->type == JOB_VERIFY_ACTIVE ||
433 j->type == JOB_RELOAD) {
435 /* Immediate result is that the job is or might be
436 * started. In this case lets wait for the
437 * dependencies, regardless whether they are
438 * starting or stopping something. */
440 SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
445 /* Also, if something else is being stopped and we should
446 * change state after it, then lets wait. */
448 SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
450 (other->job->type == JOB_STOP ||
451 other->job->type == JOB_RESTART))
454 /* This means that for a service a and a service b where b
455 * shall be started after a:
457 * start a + start b → 1st step start a, 2nd step start b
458 * start a + stop b → 1st step stop b, 2nd step start a
459 * stop a + start b → 1st step stop a, 2nd step start b
460 * stop a + stop b → 1st step stop b, 2nd step stop a
462 * This has the side effect that restarts are properly
463 * synchronized too. */
468 static void job_change_type(Job *j, JobType newtype) {
469 log_debug_unit(j->unit->id,
470 "Converting job %s/%s -> %s/%s",
471 j->unit->id, job_type_to_string(j->type),
472 j->unit->id, job_type_to_string(newtype));
477 int job_run_and_invalidate(Job *j) {
483 assert(j->installed);
484 assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
485 assert(j->in_run_queue);
487 LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
488 j->in_run_queue = false;
490 if (j->state != JOB_WAITING)
493 if (!job_is_runnable(j))
496 j->state = JOB_RUNNING;
497 job_add_to_dbus_queue(j);
499 /* While we execute this operation the job might go away (for
500 * example: because it is replaced by a new, conflicting
501 * job.) To make sure we don't access a freed job later on we
502 * store the id here, so that we can verify the job is still
510 r = unit_start(j->unit);
512 /* If this unit cannot be started, then simply wait */
517 case JOB_VERIFY_ACTIVE: {
518 UnitActiveState t = unit_active_state(j->unit);
519 if (UNIT_IS_ACTIVE_OR_RELOADING(t))
521 else if (t == UNIT_ACTIVATING)
530 r = unit_stop(j->unit);
532 /* If this unit cannot stopped, then simply wait. */
538 r = unit_reload(j->unit);
546 assert_not_reached("Unknown job type");
549 j = manager_get_job(m, id);
552 r = job_finish_and_invalidate(j, JOB_DONE, true);
553 else if (r == -ENOEXEC)
554 r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
555 else if (r == -EAGAIN)
556 j->state = JOB_WAITING;
558 r = job_finish_and_invalidate(j, JOB_FAILED, true);
564 static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
565 const UnitStatusMessageFormats *format_table;
569 assert(t < _JOB_TYPE_MAX);
571 format_table = &UNIT_VTABLE(u)->status_message_formats;
576 return format_table->finished_start_job[result];
577 else if (t == JOB_STOP || t == JOB_RESTART)
578 return format_table->finished_stop_job[result];
583 static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
588 assert(t < _JOB_TYPE_MAX);
590 format = job_get_status_message_format(u, t, result);
594 /* Return generic strings */
595 if (t == JOB_START) {
596 if (result == JOB_DONE)
597 return "Started %s.";
598 else if (result == JOB_FAILED)
599 return "Failed to start %s.";
600 else if (result == JOB_DEPENDENCY)
601 return "Dependency failed for %s.";
602 else if (result == JOB_TIMEOUT)
603 return "Timed out starting %s.";
604 } else if (t == JOB_STOP || t == JOB_RESTART) {
605 if (result == JOB_DONE)
606 return "Stopped %s.";
607 else if (result == JOB_FAILED)
608 return "Stopped (with error) %s.";
609 else if (result == JOB_TIMEOUT)
610 return "Timed out stoppping %s.";
611 } else if (t == JOB_RELOAD) {
612 if (result == JOB_DONE)
613 return "Reloaded %s.";
614 else if (result == JOB_FAILED)
615 return "Reload failed for %s.";
616 else if (result == JOB_TIMEOUT)
617 return "Timed out reloading %s.";
623 static void job_print_status_message(Unit *u, JobType t, JobResult result) {
628 assert(t < _JOB_TYPE_MAX);
630 if (t == JOB_START) {
631 format = job_get_status_message_format(u, t, result);
638 if (u->condition_result)
639 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
643 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
644 unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
648 unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
652 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
659 } else if (t == JOB_STOP || t == JOB_RESTART) {
661 format = job_get_status_message_format(u, t, result);
668 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
673 unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
680 } else if (t == JOB_VERIFY_ACTIVE) {
682 /* When verify-active detects the unit is inactive, report it.
683 * Most likely a DEPEND warning from a requisiting unit will
684 * occur next and it's nice to see what was requisited. */
685 if (result == JOB_SKIPPED)
686 unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.", unit_description(u));
690 #pragma GCC diagnostic push
691 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
692 static void job_log_status_message(Unit *u, JobType t, JobResult result) {
698 assert(t < _JOB_TYPE_MAX);
700 /* Skip this if it goes to the console. since we already print
701 * to the console anyway... */
703 if (log_on_console())
706 format = job_get_status_message_format_try_harder(u, t, result);
710 snprintf(buf, sizeof(buf), format, unit_description(u));
713 if (t == JOB_START) {
716 mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
717 log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
720 "RESULT=%s", job_result_to_string(result),
724 } else if (t == JOB_STOP)
725 log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
727 MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
728 "RESULT=%s", job_result_to_string(result),
732 else if (t == JOB_RELOAD)
733 log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
735 MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
736 "RESULT=%s", job_result_to_string(result),
740 #pragma GCC diagnostic pop
742 int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
749 assert(j->installed);
750 assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
757 log_debug_unit(u->id, "Job %s/%s finished, result=%s",
758 u->id, job_type_to_string(t), job_result_to_string(result));
760 job_print_status_message(u, t, result);
761 job_log_status_message(u, t, result);
763 job_add_to_dbus_queue(j);
765 /* Patch restart jobs so that they become normal start jobs */
766 if (result == JOB_DONE && t == JOB_RESTART) {
768 job_change_type(j, JOB_START);
769 j->state = JOB_WAITING;
771 job_add_to_run_queue(j);
776 if (result == JOB_FAILED)
777 j->manager->n_failed_jobs ++;
782 /* Fail depending jobs on failure */
783 if (result != JOB_DONE && recursive) {
785 if (t == JOB_START ||
786 t == JOB_VERIFY_ACTIVE) {
788 SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
790 (other->job->type == JOB_START ||
791 other->job->type == JOB_VERIFY_ACTIVE))
792 job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
794 SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
796 (other->job->type == JOB_START ||
797 other->job->type == JOB_VERIFY_ACTIVE))
798 job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
800 SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
802 !other->job->override &&
803 (other->job->type == JOB_START ||
804 other->job->type == JOB_VERIFY_ACTIVE))
805 job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
807 } else if (t == JOB_STOP) {
809 SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
811 (other->job->type == JOB_START ||
812 other->job->type == JOB_VERIFY_ACTIVE))
813 job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
817 /* Trigger OnFailure dependencies that are not generated by
818 * the unit itself. We don't treat JOB_CANCELED as failure in
819 * this context. And JOB_FAILURE is already handled by the
821 if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
822 log_struct_unit(LOG_NOTICE,
824 "JOB_TYPE=%s", job_type_to_string(t),
825 "JOB_RESULT=%s", job_result_to_string(result),
826 "Job %s/%s failed with result '%s'.",
828 job_type_to_string(t),
829 job_result_to_string(result),
832 unit_trigger_on_failure(u);
836 /* Try to start the next jobs that can be started */
837 SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
839 job_add_to_run_queue(other->job);
840 SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
842 job_add_to_run_queue(other->job);
844 manager_check_finished(u->manager);
849 int job_start_timer(Job *j) {
850 struct itimerspec its;
851 struct epoll_event ev;
855 if (j->unit->job_timeout <= 0 ||
856 j->timer_watch.type == WATCH_JOB_TIMER)
859 assert(j->timer_watch.type == WATCH_INVALID);
861 if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
867 timespec_store(&its.it_value, j->unit->job_timeout);
869 if (timerfd_settime(fd, 0, &its, NULL) < 0) {
875 ev.data.ptr = &j->timer_watch;
878 if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
883 j->timer_watch.type = WATCH_JOB_TIMER;
884 j->timer_watch.fd = fd;
885 j->timer_watch.data.job = j;
891 close_nointr_nofail(fd);
896 void job_add_to_run_queue(Job *j) {
898 assert(j->installed);
903 LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
904 j->in_run_queue = true;
907 void job_add_to_dbus_queue(Job *j) {
909 assert(j->installed);
911 if (j->in_dbus_queue)
914 /* We don't check if anybody is subscribed here, since this
915 * job might just have been created and not yet assigned to a
916 * connection/client. */
918 LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
919 j->in_dbus_queue = true;
922 char *job_dbus_path(Job *j) {
927 if (asprintf(&p, "/org/freedesktop/systemd1/job/%lu", (unsigned long) j->id) < 0)
933 void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
935 assert(w == &j->timer_watch);
937 log_warning_unit(j->unit->id, "Job %s/%s timed out.",
938 j->unit->id, job_type_to_string(j->type));
939 job_finish_and_invalidate(j, JOB_TIMEOUT, true);
942 int job_serialize(Job *j, FILE *f, FDSet *fds) {
943 fprintf(f, "job-id=%u\n", j->id);
944 fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
945 fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
946 fprintf(f, "job-override=%s\n", yes_no(j->override));
947 fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
948 fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
949 /* Cannot save bus clients. Just note the fact that we're losing
950 * them. job_send_message() will fallback to broadcasting. */
951 fprintf(f, "job-forgot-bus-clients=%s\n",
952 yes_no(j->forgot_bus_clients || j->bus_client_list));
953 if (j->timer_watch.type == WATCH_JOB_TIMER) {
954 int copy = fdset_put_dup(fds, j->timer_watch.fd);
957 fprintf(f, "job-timer-watch-fd=%d\n", copy);
965 int job_deserialize(Job *j, FILE *f, FDSet *fds) {
967 char line[LINE_MAX], *l, *v;
970 if (!fgets(line, sizeof(line), f)) {
991 if (streq(l, "job-id")) {
992 if (safe_atou32(v, &j->id) < 0)
993 log_debug("Failed to parse job id value %s", v);
994 } else if (streq(l, "job-type")) {
995 JobType t = job_type_from_string(v);
997 log_debug("Failed to parse job type %s", v);
998 else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
999 log_debug("Cannot deserialize job of type %s", v);
1002 } else if (streq(l, "job-state")) {
1003 JobState s = job_state_from_string(v);
1005 log_debug("Failed to parse job state %s", v);
1008 } else if (streq(l, "job-override")) {
1009 int b = parse_boolean(v);
1011 log_debug("Failed to parse job override flag %s", v);
1013 j->override = j->override || b;
1014 } else if (streq(l, "job-sent-dbus-new-signal")) {
1015 int b = parse_boolean(v);
1017 log_debug("Failed to parse job sent_dbus_new_signal flag %s", v);
1019 j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
1020 } else if (streq(l, "job-ignore-order")) {
1021 int b = parse_boolean(v);
1023 log_debug("Failed to parse job ignore_order flag %s", v);
1025 j->ignore_order = j->ignore_order || b;
1026 } else if (streq(l, "job-forgot-bus-clients")) {
1027 int b = parse_boolean(v);
1029 log_debug("Failed to parse job forgot_bus_clients flag %s", v);
1031 j->forgot_bus_clients = j->forgot_bus_clients || b;
1032 } else if (streq(l, "job-timer-watch-fd")) {
1034 if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
1035 log_debug("Failed to parse job-timer-watch-fd value %s", v);
1037 if (j->timer_watch.type == WATCH_JOB_TIMER)
1038 close_nointr_nofail(j->timer_watch.fd);
1040 j->timer_watch.type = WATCH_JOB_TIMER;
1041 j->timer_watch.fd = fdset_remove(fds, fd);
1042 j->timer_watch.data.job = j;
1048 int job_coldplug(Job *j) {
1049 struct epoll_event ev;
1051 if (j->timer_watch.type != WATCH_JOB_TIMER)
1055 ev.data.ptr = &j->timer_watch;
1056 ev.events = EPOLLIN;
1058 if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, j->timer_watch.fd, &ev) < 0)
1064 static const char* const job_state_table[_JOB_STATE_MAX] = {
1065 [JOB_WAITING] = "waiting",
1066 [JOB_RUNNING] = "running"
1069 DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
1071 static const char* const job_type_table[_JOB_TYPE_MAX] = {
1072 [JOB_START] = "start",
1073 [JOB_VERIFY_ACTIVE] = "verify-active",
1074 [JOB_STOP] = "stop",
1075 [JOB_RELOAD] = "reload",
1076 [JOB_RELOAD_OR_START] = "reload-or-start",
1077 [JOB_RESTART] = "restart",
1078 [JOB_TRY_RESTART] = "try-restart",
1082 DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
1084 static const char* const job_mode_table[_JOB_MODE_MAX] = {
1085 [JOB_FAIL] = "fail",
1086 [JOB_REPLACE] = "replace",
1087 [JOB_ISOLATE] = "isolate",
1088 [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
1089 [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
1092 DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
1094 static const char* const job_result_table[_JOB_RESULT_MAX] = {
1095 [JOB_DONE] = "done",
1096 [JOB_CANCELED] = "canceled",
1097 [JOB_TIMEOUT] = "timeout",
1098 [JOB_FAILED] = "failed",
1099 [JOB_DEPENDENCY] = "dependency",
1100 [JOB_SKIPPED] = "skipped"
1103 DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);