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>
28 #include "sd-messages.h"
33 #include "load-fragment.h"
34 #include "load-dropin.h"
40 #include "dbus-client-track.h"
42 Job* job_new_raw(Unit *unit) {
45 /* used for deserialization */
53 j->manager = unit->manager;
55 j->type = _JOB_TYPE_INVALID;
60 Job* job_new(Unit *unit, JobType type) {
63 assert(type < _JOB_TYPE_MAX);
65 j = job_new_raw(unit);
69 j->id = j->manager->current_job_id++;
72 /* We don't link it here, that's what job_dependency() is for */
77 void job_free(Job *j) {
79 assert(!j->installed);
80 assert(!j->transaction_prev);
81 assert(!j->transaction_next);
82 assert(!j->subject_list);
83 assert(!j->object_list);
86 LIST_REMOVE(run_queue, j->manager->run_queue, j);
89 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
91 sd_event_source_unref(j->timer_event_source);
93 bus_client_track_free(j->subscribed);
98 void job_uninstall(Job *j) {
101 assert(j->installed);
103 pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
106 /* Detach from next 'bigger' objects */
108 /* daemon-reload should be transparent to job observers */
109 if (j->manager->n_reloading <= 0)
110 bus_job_send_removed_signal(j);
114 unit_add_to_gc_queue(j->unit);
116 hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
117 j->installed = false;
120 static bool job_type_allows_late_merge(JobType t) {
121 /* Tells whether it is OK to merge a job of type 't' with an already
123 * Reloads cannot be merged this way. Think of the sequence:
124 * 1. Reload of a daemon is in progress; the daemon has already loaded
125 * its config file, but hasn't completed the reload operation yet.
126 * 2. Edit foo's config file.
127 * 3. Trigger another reload to have the daemon use the new config.
128 * Should the second reload job be merged into the first one, the daemon
129 * would not know about the new config.
130 * JOB_RESTART jobs on the other hand can be merged, because they get
131 * patched into JOB_START after stopping the unit. So if we see a
132 * JOB_RESTART running, it means the unit hasn't stopped yet and at
133 * this time the merge is still allowed. */
134 return t != JOB_RELOAD;
137 static void job_merge_into_installed(Job *j, Job *other) {
138 assert(j->installed);
139 assert(j->unit == other->unit);
141 if (j->type != JOB_NOP)
142 job_type_merge_and_collapse(&j->type, other->type, j->unit);
144 assert(other->type == JOB_NOP);
146 j->override = j->override || other->override;
147 j->irreversible = j->irreversible || other->irreversible;
148 j->ignore_order = j->ignore_order || other->ignore_order;
151 Job* job_install(Job *j) {
155 assert(!j->installed);
156 assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
158 pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
162 if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
163 job_finish_and_invalidate(uj, JOB_CANCELED, false);
165 /* not conflicting, i.e. mergeable */
167 if (j->type == JOB_NOP || uj->state == JOB_WAITING ||
168 (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
169 job_merge_into_installed(uj, j);
170 log_debug_unit(uj->unit->id,
171 "Merged into installed job %s/%s as %u",
172 uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
175 /* already running and not safe to merge into */
176 /* Patch uj to become a merged job and re-run it. */
177 /* XXX It should be safer to queue j to run after uj finishes, but it is
178 * not currently possible to have more than one installed job per unit. */
179 job_merge_into_installed(uj, j);
180 log_debug_unit(uj->unit->id,
181 "Merged into running job, re-running: %s/%s as %u",
182 uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
183 uj->state = JOB_WAITING;
184 uj->manager->n_running_jobs--;
190 /* Install the job */
193 j->manager->n_installed_jobs ++;
194 log_debug_unit(j->unit->id,
195 "Installed new job %s/%s as %u",
196 j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
200 int job_install_deserialized(Job *j) {
203 assert(!j->installed);
205 if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
206 log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
210 pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
213 log_debug_unit(j->unit->id,
214 "Unit %s already has a job installed. Not installing deserialized job.",
220 log_debug_unit(j->unit->id,
221 "Reinstalled deserialized job %s/%s as %u",
222 j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
226 JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
231 /* Adds a new job link, which encodes that the 'subject' job
232 * needs the 'object' job in some way. If 'subject' is NULL
233 * this means the 'anchor' job (i.e. the one the user
234 * explicitly asked for) is the requester. */
236 if (!(l = new0(JobDependency, 1)))
239 l->subject = subject;
241 l->matters = matters;
242 l->conflicts = conflicts;
245 LIST_PREPEND(subject, subject->subject_list, l);
247 LIST_PREPEND(object, object->object_list, l);
252 void job_dependency_free(JobDependency *l) {
256 LIST_REMOVE(subject, l->subject->subject_list, l);
258 LIST_REMOVE(object, l->object->object_list, l);
263 void job_dump(Job *j, FILE*f, const char *prefix) {
272 "%s\tAction: %s -> %s\n"
275 "%s\tIrreversible: %s\n",
277 prefix, j->unit->id, job_type_to_string(j->type),
278 prefix, job_state_to_string(j->state),
279 prefix, yes_no(j->override),
280 prefix, yes_no(j->irreversible));
284 * Merging is commutative, so imagine the matrix as symmetric. We store only
285 * its lower triangle to avoid duplication. We don't store the main diagonal,
286 * because A merged with A is simply A.
288 * If the resulting type is collapsed immediately afterwards (to get rid of
289 * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
290 * the following properties hold:
292 * Merging is associative! A merged with B merged with C is the same as
293 * A merged with C merged with B.
295 * Mergeability is transitive! If A can be merged with B and B with C then
298 * Also, if A merged with B cannot be merged with C, then either A or B cannot
299 * be merged with C either.
301 static const JobType job_merging_table[] = {
302 /* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */
303 /*********************************************************************************/
305 /*JOB_VERIFY_ACTIVE */ JOB_START,
306 /*JOB_STOP */ -1, -1,
307 /*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
308 /*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART,
311 JobType job_type_lookup_merge(JobType a, JobType b) {
312 assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
313 assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
314 assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
325 return job_merging_table[(a - 1) * a / 2 + b];
328 bool job_type_is_redundant(JobType a, UnitActiveState b) {
338 b == UNIT_INACTIVE ||
341 case JOB_VERIFY_ACTIVE:
352 b == UNIT_ACTIVATING;
355 assert_not_reached("Invalid job type");
359 void job_type_collapse(JobType *t, Unit *u) {
364 case JOB_TRY_RESTART:
365 s = unit_active_state(u);
366 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
372 case JOB_RELOAD_OR_START:
373 s = unit_active_state(u);
374 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
385 int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
386 JobType t = job_type_lookup_merge(*a, b);
390 job_type_collapse(a, u);
394 static bool job_is_runnable(Job *j) {
399 assert(j->installed);
401 /* Checks whether there is any job running for the units this
402 * job needs to be running after (in the case of a 'positive'
403 * job type) or before (in the case of a 'negative' job
406 /* Note that unit types have a say in what is runnable,
407 * too. For example, if they return -EAGAIN from
408 * unit_start() they can indicate they are not
411 /* First check if there is an override */
415 if (j->type == JOB_NOP)
418 if (j->type == JOB_START ||
419 j->type == JOB_VERIFY_ACTIVE ||
420 j->type == JOB_RELOAD) {
422 /* Immediate result is that the job is or might be
423 * started. In this case lets wait for the
424 * dependencies, regardless whether they are
425 * starting or stopping something. */
427 SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
432 /* Also, if something else is being stopped and we should
433 * change state after it, then lets wait. */
435 SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
437 (other->job->type == JOB_STOP ||
438 other->job->type == JOB_RESTART))
441 /* This means that for a service a and a service b where b
442 * shall be started after a:
444 * start a + start b → 1st step start a, 2nd step start b
445 * start a + stop b → 1st step stop b, 2nd step start a
446 * stop a + start b → 1st step stop a, 2nd step start b
447 * stop a + stop b → 1st step stop b, 2nd step stop a
449 * This has the side effect that restarts are properly
450 * synchronized too. */
455 static void job_change_type(Job *j, JobType newtype) {
456 log_debug_unit(j->unit->id,
457 "Converting job %s/%s -> %s/%s",
458 j->unit->id, job_type_to_string(j->type),
459 j->unit->id, job_type_to_string(newtype));
464 int job_run_and_invalidate(Job *j) {
467 Manager *m = j->manager;
470 assert(j->installed);
471 assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
472 assert(j->in_run_queue);
474 LIST_REMOVE(run_queue, j->manager->run_queue, j);
475 j->in_run_queue = false;
477 if (j->state != JOB_WAITING)
480 if (!job_is_runnable(j))
483 j->state = JOB_RUNNING;
485 job_add_to_dbus_queue(j);
487 /* While we execute this operation the job might go away (for
488 * example: because it is replaced by a new, conflicting
489 * job.) To make sure we don't access a freed job later on we
490 * store the id here, so that we can verify the job is still
497 r = unit_start(j->unit);
499 /* If this unit cannot be started, then simply wait */
504 case JOB_VERIFY_ACTIVE: {
505 UnitActiveState t = unit_active_state(j->unit);
506 if (UNIT_IS_ACTIVE_OR_RELOADING(t))
508 else if (t == UNIT_ACTIVATING)
517 r = unit_stop(j->unit);
519 /* If this unit cannot stopped, then simply wait. */
525 r = unit_reload(j->unit);
533 assert_not_reached("Unknown job type");
536 j = manager_get_job(m, id);
539 r = job_finish_and_invalidate(j, JOB_DONE, true);
540 else if (r == -EBADR)
541 r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
542 else if (r == -ENOEXEC)
543 r = job_finish_and_invalidate(j, JOB_INVALID, true);
544 else if (r == -EAGAIN) {
545 j->state = JOB_WAITING;
548 r = job_finish_and_invalidate(j, JOB_FAILED, true);
554 _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
555 const UnitStatusMessageFormats *format_table;
559 assert(t < _JOB_TYPE_MAX);
561 format_table = &UNIT_VTABLE(u)->status_message_formats;
566 return format_table->finished_start_job[result];
567 else if (t == JOB_STOP || t == JOB_RESTART)
568 return format_table->finished_stop_job[result];
573 _pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
578 assert(t < _JOB_TYPE_MAX);
580 format = job_get_status_message_format(u, t, result);
584 /* Return generic strings */
585 if (t == JOB_START) {
586 if (result == JOB_DONE)
587 return "Started %s.";
588 else if (result == JOB_FAILED)
589 return "Failed to start %s.";
590 else if (result == JOB_DEPENDENCY)
591 return "Dependency failed for %s.";
592 else if (result == JOB_TIMEOUT)
593 return "Timed out starting %s.";
594 } else if (t == JOB_STOP || t == JOB_RESTART) {
595 if (result == JOB_DONE)
596 return "Stopped %s.";
597 else if (result == JOB_FAILED)
598 return "Stopped (with error) %s.";
599 else if (result == JOB_TIMEOUT)
600 return "Timed out stoppping %s.";
601 } else if (t == JOB_RELOAD) {
602 if (result == JOB_DONE)
603 return "Reloaded %s.";
604 else if (result == JOB_FAILED)
605 return "Reload failed for %s.";
606 else if (result == JOB_TIMEOUT)
607 return "Timed out reloading %s.";
613 #pragma GCC diagnostic push
614 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
615 static void job_print_status_message(Unit *u, JobType t, JobResult result) {
620 assert(t < _JOB_TYPE_MAX);
622 if (t == JOB_START) {
623 format = job_get_status_message_format(u, t, result);
630 if (u->condition_result)
631 unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
635 manager_flip_auto_status(u->manager, true);
636 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
637 manager_status_printf(u->manager, false, NULL, "See 'systemctl status %s' for details.", u->id);
641 manager_flip_auto_status(u->manager, true);
642 unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
646 manager_flip_auto_status(u->manager, true);
647 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
654 } else if (t == JOB_STOP || t == JOB_RESTART) {
656 format = job_get_status_message_format(u, t, result);
663 manager_flip_auto_status(u->manager, true);
664 unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
669 unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
676 } else if (t == JOB_VERIFY_ACTIVE) {
678 /* When verify-active detects the unit is inactive, report it.
679 * Most likely a DEPEND warning from a requisiting unit will
680 * occur next and it's nice to see what was requisited. */
681 if (result == JOB_SKIPPED)
682 unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
685 #pragma GCC diagnostic pop
687 #pragma GCC diagnostic push
688 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
689 static void job_log_status_message(Unit *u, JobType t, JobResult result) {
695 assert(t < _JOB_TYPE_MAX);
697 /* Skip this if it goes to the console. since we already print
698 * to the console anyway... */
700 if (log_on_console())
703 format = job_get_status_message_format_try_harder(u, t, result);
707 snprintf(buf, sizeof(buf), format, unit_description(u));
710 if (t == JOB_START) {
713 mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
714 log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
717 "RESULT=%s", job_result_to_string(result),
721 } else if (t == JOB_STOP)
722 log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
724 MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
725 "RESULT=%s", job_result_to_string(result),
729 else if (t == JOB_RELOAD)
730 log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
732 MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
733 "RESULT=%s", job_result_to_string(result),
737 #pragma GCC diagnostic pop
739 int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
746 assert(j->installed);
747 assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
754 if (j->state == JOB_RUNNING)
755 j->manager->n_running_jobs--;
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 || result == JOB_INVALID)
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_start_on_failure(u);
835 unit_trigger_notify(u);
838 /* Try to start the next jobs that can be started */
839 SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
841 job_add_to_run_queue(other->job);
842 SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
844 job_add_to_run_queue(other->job);
846 manager_check_finished(u->manager);
851 static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) {
855 assert(s == j->timer_event_source);
857 log_warning_unit(j->unit->id, "Job %s/%s timed out.",
858 j->unit->id, job_type_to_string(j->type));
860 job_finish_and_invalidate(j, JOB_TIMEOUT, true);
864 int job_start_timer(Job *j) {
867 if (j->timer_event_source)
870 j->begin_usec = now(CLOCK_MONOTONIC);
872 if (j->unit->job_timeout <= 0)
875 r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source);
882 void job_add_to_run_queue(Job *j) {
884 assert(j->installed);
889 if (!j->manager->run_queue)
890 sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
892 LIST_PREPEND(run_queue, j->manager->run_queue, j);
893 j->in_run_queue = true;
896 void job_add_to_dbus_queue(Job *j) {
898 assert(j->installed);
900 if (j->in_dbus_queue)
903 /* We don't check if anybody is subscribed here, since this
904 * job might just have been created and not yet assigned to a
905 * connection/client. */
907 LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j);
908 j->in_dbus_queue = true;
911 char *job_dbus_path(Job *j) {
916 if (asprintf(&p, "/org/freedesktop/systemd1/job/%"PRIu32, j->id) < 0)
922 int job_serialize(Job *j, FILE *f, FDSet *fds) {
923 fprintf(f, "job-id=%u\n", j->id);
924 fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
925 fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
926 fprintf(f, "job-override=%s\n", yes_no(j->override));
927 fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
928 fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
929 fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
931 if (j->begin_usec > 0)
932 fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
934 bus_client_track_serialize(j->manager, f, j->subscribed);
941 int job_deserialize(Job *j, FILE *f, FDSet *fds) {
945 char line[LINE_MAX], *l, *v;
948 if (!fgets(line, sizeof(line), f)) {
969 if (streq(l, "job-id")) {
971 if (safe_atou32(v, &j->id) < 0)
972 log_debug("Failed to parse job id value %s", v);
974 } else if (streq(l, "job-type")) {
977 t = job_type_from_string(v);
979 log_debug("Failed to parse job type %s", v);
980 else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
981 log_debug("Cannot deserialize job of type %s", v);
985 } else if (streq(l, "job-state")) {
988 s = job_state_from_string(v);
990 log_debug("Failed to parse job state %s", v);
994 } else if (streq(l, "job-override")) {
997 b = parse_boolean(v);
999 log_debug("Failed to parse job override flag %s", v);
1001 j->override = j->override || b;
1003 } else if (streq(l, "job-irreversible")) {
1006 b = parse_boolean(v);
1008 log_debug("Failed to parse job irreversible flag %s", v);
1010 j->irreversible = j->irreversible || b;
1012 } else if (streq(l, "job-sent-dbus-new-signal")) {
1015 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;
1021 } else if (streq(l, "job-ignore-order")) {
1024 b = parse_boolean(v);
1026 log_debug("Failed to parse job ignore_order flag %s", v);
1028 j->ignore_order = j->ignore_order || b;
1030 } else if (streq(l, "job-begin")) {
1031 unsigned long long ull;
1033 if (sscanf(v, "%llu", &ull) != 1)
1034 log_debug("Failed to parse job-begin value %s", v);
1036 j->begin_usec = ull;
1039 char t[strlen(l) + 1 + strlen(v) + 1];
1041 strcpy(stpcpy(stpcpy(t, l), "="), v);
1043 if (bus_client_track_deserialize_item(j->manager, &j->subscribed, t) == 0)
1044 log_debug("Unknown deserialization key '%s'", l);
1049 int job_coldplug(Job *j) {
1054 if (j->begin_usec == 0 || j->unit->job_timeout == 0)
1057 if (j->timer_event_source)
1058 j->timer_event_source = sd_event_source_unref(j->timer_event_source);
1060 r = sd_event_add_monotonic(j->manager->event, j->begin_usec + j->unit->job_timeout, 0, job_dispatch_timer, j, &j->timer_event_source);
1062 log_debug("Failed to restart timeout for job: %s", strerror(-r));
1067 void job_shutdown_magic(Job *j) {
1070 /* The shutdown target gets some special treatment here: we
1071 * tell the kernel to begin with flushing its disk caches, to
1072 * optimize shutdown time a bit. Ideally we wouldn't hardcode
1073 * this magic into PID 1. However all other processes aren't
1074 * options either since they'd exit much sooner than PID 1 and
1075 * asynchronous sync() would cause their exit to be
1078 if (j->type != JOB_START)
1081 if (j->unit->manager->running_as != SYSTEMD_SYSTEM)
1084 if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
1087 /* In case messages on console has been disabled on boot */
1088 j->unit->manager->no_console_output = false;
1090 if (detect_container(NULL) > 0)
1093 asynchronous_sync();
1096 int job_get_timeout(Job *j, uint64_t *timeout) {
1098 uint64_t x = -1, y = -1;
1103 if (j->timer_event_source) {
1104 r = sd_event_source_get_time(j->timer_event_source, &x);
1110 if (UNIT_VTABLE(u)->get_timeout) {
1111 q = UNIT_VTABLE(u)->get_timeout(u, &y);
1116 if (r == 0 && q == 0)
1119 *timeout = MIN(x, y);
1124 static const char* const job_state_table[_JOB_STATE_MAX] = {
1125 [JOB_WAITING] = "waiting",
1126 [JOB_RUNNING] = "running"
1129 DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
1131 static const char* const job_type_table[_JOB_TYPE_MAX] = {
1132 [JOB_START] = "start",
1133 [JOB_VERIFY_ACTIVE] = "verify-active",
1134 [JOB_STOP] = "stop",
1135 [JOB_RELOAD] = "reload",
1136 [JOB_RELOAD_OR_START] = "reload-or-start",
1137 [JOB_RESTART] = "restart",
1138 [JOB_TRY_RESTART] = "try-restart",
1142 DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
1144 static const char* const job_mode_table[_JOB_MODE_MAX] = {
1145 [JOB_FAIL] = "fail",
1146 [JOB_REPLACE] = "replace",
1147 [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
1148 [JOB_ISOLATE] = "isolate",
1149 [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
1150 [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
1151 [JOB_FLUSH] = "flush",
1154 DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
1156 static const char* const job_result_table[_JOB_RESULT_MAX] = {
1157 [JOB_DONE] = "done",
1158 [JOB_CANCELED] = "canceled",
1159 [JOB_TIMEOUT] = "timeout",
1160 [JOB_FAILED] = "failed",
1161 [JOB_DEPENDENCY] = "dependency",
1162 [JOB_SKIPPED] = "skipped",
1163 [JOB_INVALID] = "invalid",
1166 DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);