+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
assert(j);
assert(f);
- if (!prefix)
- prefix = "";
+ prefix = strempty(prefix);
fprintf(f,
"%s-> Job %u:\n"
"%s\tAction: %s -> %s\n"
"%s\tState: %s\n"
- "%s\tIrreversible: %s\n",
+ "%s\tIrreversible: %s\n"
+ "%s\tMay GC: %s\n",
prefix, j->id,
prefix, j->unit->id, job_type_to_string(j->type),
prefix, job_state_to_string(j->state),
- prefix, yes_no(j->irreversible));
+ prefix, yes_no(j->irreversible),
+ prefix, yes_no(job_may_gc(j)));
}
/*
switch (a) {
case JOB_START:
- return
- b == UNIT_ACTIVE ||
- b == UNIT_RELOADING;
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_STOP:
- return
- b == UNIT_INACTIVE ||
- b == UNIT_FAILED;
+ return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
case JOB_VERIFY_ACTIVE:
- return
- b == UNIT_ACTIVE ||
- b == UNIT_RELOADING;
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_RELOAD:
return
static bool job_is_runnable(Job *j) {
Iterator i;
Unit *other;
+ void *v;
assert(j);
assert(j->installed);
return true;
if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
-
/* Immediate result is that the job is or might be
* started. In this case let's wait for the
* dependencies, regardless whether they are
* starting or stopping something. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i)
if (other->job)
return false;
}
/* Also, if something else is being stopped and we should
* change state after it, then let's wait. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i)
if (other->job &&
IN_SET(other->job->type, JOB_STOP, JOB_RESTART))
return false;
case JOB_RESTART:
t = JOB_STOP;
- /* fall through */
+ _fallthrough_;
case JOB_STOP:
r = unit_stop(u);
break;
/* Return generic strings */
if (t == JOB_START)
return generic_finished_start_job[result];
- else if (t == JOB_STOP || t == JOB_RESTART)
+ else if (IN_SET(t, JOB_STOP, JOB_RESTART))
return generic_finished_stop_job[result];
else if (t == JOB_RELOAD)
return generic_finished_reload_job[result];
return NULL;
}
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- static const struct {
- const char *color, *word;
- } statuses[_JOB_RESULT_MAX] = {
- [JOB_DONE] = { ANSI_GREEN, " OK " },
- [JOB_TIMEOUT] = { ANSI_HIGHLIGHT_RED, " TIME " },
- [JOB_FAILED] = { ANSI_HIGHLIGHT_RED, "FAILED" },
- [JOB_DEPENDENCY] = { ANSI_HIGHLIGHT_YELLOW, "DEPEND" },
- [JOB_SKIPPED] = { ANSI_HIGHLIGHT, " INFO " },
- [JOB_ASSERT] = { ANSI_HIGHLIGHT_YELLOW, "ASSERT" },
- [JOB_UNSUPPORTED] = { ANSI_HIGHLIGHT_YELLOW, "UNSUPP" },
- [JOB_COLLECTED] = { ANSI_HIGHLIGHT, " INFO " },
- };
+static const struct {
+ const char *color, *word;
+} job_print_status_messages [_JOB_RESULT_MAX] = {
+ [JOB_DONE] = { ANSI_OK_COLOR, " OK " },
+ [JOB_TIMEOUT] = { ANSI_HIGHLIGHT_RED, " TIME " },
+ [JOB_FAILED] = { ANSI_HIGHLIGHT_RED, "FAILED" },
+ [JOB_DEPENDENCY] = { ANSI_HIGHLIGHT_YELLOW, "DEPEND" },
+ [JOB_SKIPPED] = { ANSI_HIGHLIGHT, " INFO " },
+ [JOB_ASSERT] = { ANSI_HIGHLIGHT_YELLOW, "ASSERT" },
+ [JOB_UNSUPPORTED] = { ANSI_HIGHLIGHT_YELLOW, "UNSUPP" },
+ /* JOB_COLLECTED */
+};
+static void job_print_status_message(Unit *u, JobType t, JobResult result) {
const char *format;
const char *status;
if (t == JOB_RELOAD)
return;
+ if (!job_print_status_messages[result].word)
+ return;
+
format = job_get_status_message_format(u, t, result);
if (!format)
return;
if (log_get_show_color())
- status = strjoina(statuses[result].color, statuses[result].word, ANSI_NORMAL);
+ status = strjoina(job_print_status_messages[result].color,
+ job_print_status_messages[result].word,
+ ANSI_NORMAL);
else
- status = statuses[result].word;
+ status = job_print_status_messages[result].word;
if (result != JOB_DONE)
manager_flip_auto_status(u->manager, true);
if (t == JOB_START && result == JOB_FAILED) {
_cleanup_free_ char *quoted;
- quoted = shell_maybe_quote(u->id);
+ quoted = shell_maybe_quote(u->id, ESCAPE_BACKSLASH);
manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
}
}
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
- /* Skip this if it goes to the console. since we already print
- * to the console anyway... */
-
- if (log_on_console())
+ /* Skip printing if output goes to the console, and job_print_status_message()
+ will actually print something to the console. */
+ if (log_on_console() && job_print_status_messages[result].word)
return;
format = job_get_status_message_format(u, t, result);
if (!format)
return;
- /* The description might be longer than the buffer, but that's OK, we'll just truncate it here */
+ /* The description might be longer than the buffer, but that's OK,
+ * we'll just truncate it here. Note that we use snprintf() rather than
+ * xsprintf() on purpose here: we are fine with truncation and don't
+ * consider that an error. */
DISABLE_WARNING_FORMAT_NONLITERAL;
- snprintf(buf, sizeof(buf), format, unit_description(u));
+ (void) snprintf(buf, sizeof(buf), format, unit_description(u));
REENABLE_WARNING;
switch (t) {
default:
log_struct(job_result_log_level[result],
LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
NULL);
return;
}
log_struct(job_result_log_level[result],
LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
mid,
NULL);
}
static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
+ assert(u);
/* No message if the job did not actually do anything due to failed condition. */
if (t == JOB_START && result == JOB_DONE && !u->condition_result)
static void job_fail_dependencies(Unit *u, UnitDependency d) {
Unit *other;
Iterator i;
+ void *v;
assert(u);
- SET_FOREACH(other, u->dependencies[d], i) {
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[d], i) {
Job *j = other->job;
if (!j)
Unit *other;
JobType t;
Iterator i;
+ void *v;
assert(j);
assert(j->installed);
if (!already)
job_emit_status_message(u, t, result);
- job_add_to_dbus_queue(j);
-
/* Patch restart jobs so that they become normal start jobs */
if (result == JOB_DONE && t == JOB_RESTART) {
job_change_type(j, JOB_START);
job_set_state(j, JOB_WAITING);
+ job_add_to_dbus_queue(j);
job_add_to_run_queue(j);
job_add_to_gc_queue(j);
goto finish;
}
- if (result == JOB_FAILED || result == JOB_INVALID)
+ if (IN_SET(result, JOB_FAILED, JOB_INVALID))
j->manager->n_failed_jobs++;
job_uninstall(j);
* the unit itself. We don't treat JOB_CANCELED as failure in
* this context. And JOB_FAILURE is already handled by the
* unit itself. */
- if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
+ if (IN_SET(result, JOB_TIMEOUT, JOB_DEPENDENCY)) {
log_struct(LOG_NOTICE,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
finish:
/* Try to start the next jobs that can be started */
- SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_AFTER], i)
if (other->job) {
job_add_to_run_queue(other->job);
job_add_to_gc_queue(other->job);
}
- SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
+ HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BEFORE], i)
if (other->job) {
job_add_to_run_queue(other->job);
job_add_to_gc_queue(other->job);
if (detect_container() > 0)
return;
- asynchronous_sync();
+ (void) asynchronous_sync(NULL);
}
int job_get_timeout(Job *j, usec_t *timeout) {
return 1;
}
-bool job_check_gc(Job *j) {
+bool job_may_gc(Job *j) {
Unit *other;
Iterator i;
+ void *v;
assert(j);
/* Checks whether this job should be GC'ed away. We only do this for jobs of units that have no effect on their
- * own and just track external state. For now the only unit type that qualifies for this are .device units. */
+ * own and just track external state. For now the only unit type that qualifies for this are .device units.
+ * Returns true if the job can be collected. */
if (!UNIT_VTABLE(j->unit)->gc_jobs)
- return true;
+ return false;
if (sd_bus_track_count(j->bus_track) > 0)
- return true;
+ return false;
/* FIXME: So this is a bit ugly: for now we don't properly track references made via private bus connections
* (because it's nasty, as sd_bus_track doesn't apply to it). We simply remember that the job was once
if (set_isempty(j->unit->manager->private_buses))
j->ref_by_private_bus = false;
else
- return true;
+ return false;
}
if (j->type == JOB_NOP)
- return true;
+ return false;
/* If a job is ordered after ours, and is to be started, then it needs to wait for us, regardless if we stop or
* start, hence let's not GC in that case. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
continue;
if (IN_SET(other->job->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD))
- return true;
+ return false;
}
- /* If we are going down, but something else is orederd After= us, then it needs to wait for us */
- if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) {
-
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ /* If we are going down, but something else is ordered After= us, then it needs to wait for us */
+ if (IN_SET(j->type, JOB_STOP, JOB_RESTART))
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
if (other->job->ignore_order)
continue;
- return true;
+ return false;
}
- }
/* The logic above is kinda the inverse of the job_is_runnable() logic. Specifically, if the job "we" is
* ordered before the job "other":
*
*/
- return false;
+ return true;
}
void job_add_to_gc_queue(Job *j) {
if (j->in_gc_queue)
return;
- if (job_check_gc(j))
+ if (!job_may_gc(j))
return;
LIST_PREPEND(gc_queue, j->unit->manager->gc_job_queue, j);
size_t n = 0, n_allocated = 0;
Unit *other = NULL;
Iterator i;
+ void *v;
/* Returns a list of all pending jobs that need to finish before this job may be started. */
if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
}
}
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
_cleanup_free_ Job** list = NULL;
size_t n = 0, n_allocated = 0;
Unit *other = NULL;
+ void *v;
Iterator i;
assert(j);
/* Returns a list of all pending jobs that are waiting for this job to finish. */
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) {
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
+ HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;