#include <sys/timerfd.h>
#include <sys/epoll.h>
+#include "systemd/sd-id128.h"
+#include "systemd/sd-messages.h"
#include "set.h"
#include "unit.h"
#include "macro.h"
if (uj) {
if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, true);
+ job_finish_and_invalidate(uj, JOB_CANCELED, false);
else {
/* not conflicting, i.e. mergeable */
return r;
}
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
+static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
const UnitStatusMessageFormats *format_table;
- const char *format;
+
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
format_table = &UNIT_VTABLE(u)->status_message_formats;
if (!format_table)
- return;
+ return NULL;
+
+ if (t == JOB_START)
+ return format_table->finished_start_job[result];
+ else if (t == JOB_STOP || t == JOB_RESTART)
+ return format_table->finished_stop_job[result];
+
+ return NULL;
+}
+
+static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
+ const char *format;
+
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
+
+ format = job_get_status_message_format(u, t, result);
+ if (format)
+ return format;
+ /* Return generic strings */
if (t == JOB_START) {
+ if (result == JOB_DONE)
+ return "Started %s.";
+ else if (result == JOB_FAILED)
+ return "Failed to start %s.";
+ else if (result == JOB_DEPENDENCY)
+ return "Dependency failed for %s.";
+ else if (result == JOB_TIMEOUT)
+ return "Timed out starting %s.";
+ } else if (t == JOB_STOP || t == JOB_RESTART) {
+ if (result == JOB_DONE)
+ return "Stopped %s.";
+ else if (result == JOB_FAILED)
+ return "Stopped (with error) %s.";
+ else if (result == JOB_TIMEOUT)
+ return "Timed out stoppping %s.";
+ } else if (t == JOB_RELOAD) {
+ if (result == JOB_DONE)
+ return "Reloaded %s.";
+ else if (result == JOB_FAILED)
+ return "Reload failed for %s.";
+ else if (result == JOB_TIMEOUT)
+ return "Timed out reloading %s.";
+ }
- format = format_table->finished_start_job[result];
+ return NULL;
+}
+
+static void job_print_status_message(Unit *u, JobType t, JobResult result) {
+ const char *format;
+
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
+
+ if (t == JOB_START) {
+ format = job_get_status_message_format(u, t, result);
if (!format)
return;
case JOB_FAILED:
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- unit_status_printf(u, "", "See 'systemctl status %s' for details.", u->id);
+ unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
break;
case JOB_DEPENDENCY:
} else if (t == JOB_STOP || t == JOB_RESTART) {
- format = format_table->finished_stop_job[result];
+ format = job_get_status_message_format(u, t, result);
if (!format)
return;
default:
;
}
+
+ } else if (t == JOB_VERIFY_ACTIVE) {
+
+ /* When verify-active detects the unit is inactive, report it.
+ * Most likely a DEPEND warning from a requisiting unit will
+ * occur next and it's nice to see what was requisited. */
+ if (result == JOB_SKIPPED)
+ unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.", unit_description(u));
}
}
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+static void job_log_status_message(Unit *u, JobType t, JobResult result) {
+ const char *format;
+ char buf[LINE_MAX];
+
+ assert(u);
+ 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())
+ return;
+
+ format = job_get_status_message_format_try_harder(u, t, result);
+ if (!format)
+ return;
+
+ snprintf(buf, sizeof(buf), format, unit_description(u));
+ char_array_0(buf);
+
+ if (t == JOB_START) {
+ sd_id128_t mid;
+
+ mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
+ log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ MESSAGE_ID(mid),
+ "UNIT=%s", u->id,
+ "RESULT=%s", job_result_to_string(result),
+ "MESSAGE=%s", buf,
+ NULL);
+
+ } else if (t == JOB_STOP)
+ log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
+ "UNIT=%s", u->id,
+ "RESULT=%s", job_result_to_string(result),
+ "MESSAGE=%s", buf,
+ NULL);
+
+ else if (t == JOB_RELOAD)
+ log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
+ "UNIT=%s", u->id,
+ "RESULT=%s", job_result_to_string(result),
+ "MESSAGE=%s", buf,
+ NULL);
+}
+#pragma GCC diagnostic pop
+
int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
Unit *u;
Unit *other;
log_debug("Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
job_print_status_message(u, t, result);
+ job_log_status_message(u, t, result);
job_add_to_dbus_queue(j);