chiark / gitweb /
job: fix merging with --ignore-dependencies
[elogind.git] / src / core / job.c
index 107961ae25457376fb78a98bd812223d6021f711..6a03d17aa83b62f5e4da9b66c05c6cdae49ce431 100644 (file)
@@ -24,6 +24,8 @@
 #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"
@@ -164,6 +166,7 @@ static void job_merge_into_installed(Job *j, Job *other) {
                 assert(other->type == JOB_NOP);
 
         j->override = j->override || other->override;
+        j->ignore_order = j->ignore_order || other->ignore_order;
 }
 
 Job* job_install(Job *j) {
@@ -178,15 +181,16 @@ Job* job_install(Job *j) {
 
         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 */
 
                         if (j->type == JOB_NOP || uj->state == JOB_WAITING ||
                             (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
                                 job_merge_into_installed(uj, j);
-                                log_debug("Merged into installed job %s/%s as %u",
-                                          uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
+                                log_debug_unit(uj->unit->id,
+                                               "Merged into installed job %s/%s as %u",
+                                               uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
                                 return uj;
                         } else {
                                 /* already running and not safe to merge into */
@@ -194,8 +198,9 @@ Job* job_install(Job *j) {
                                 /* XXX It should be safer to queue j to run after uj finishes, but it is
                                  * not currently possible to have more than one installed job per unit. */
                                 job_merge_into_installed(uj, j);
-                                log_debug("Merged into running job, re-running: %s/%s as %u",
-                                          uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
+                                log_debug_unit(uj->unit->id,
+                                               "Merged into running job, re-running: %s/%s as %u",
+                                               uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
                                 uj->state = JOB_WAITING;
                                 return uj;
                         }
@@ -206,7 +211,9 @@ Job* job_install(Job *j) {
         *pj = j;
         j->installed = true;
         j->manager->n_installed_jobs ++;
-        log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
+        log_debug_unit(j->unit->id,
+                       "Installed new job %s/%s as %u",
+                       j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
         return j;
 }
 
@@ -223,12 +230,16 @@ int job_install_deserialized(Job *j) {
         pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
 
         if (*pj) {
-                log_debug("Unit %s already has a job installed. Not installing deserialized job.", j->unit->id);
+                log_debug_unit(j->unit->id,
+                               "Unit %s already has a job installed. Not installing deserialized job.",
+                               j->unit->id);
                 return -EEXIST;
         }
         *pj = j;
         j->installed = true;
-        log_debug("Reinstalled deserialized job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
+        log_debug_unit(j->unit->id,
+                       "Reinstalled deserialized job %s/%s as %u",
+                       j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
         return 0;
 }
 
@@ -455,9 +466,10 @@ bool job_is_runnable(Job *j) {
 }
 
 static void job_change_type(Job *j, JobType newtype) {
-        log_debug("Converting job %s/%s -> %s/%s",
-                  j->unit->id, job_type_to_string(j->type),
-                  j->unit->id, job_type_to_string(newtype));
+        log_debug_unit(j->unit->id,
+                       "Converting job %s/%s -> %s/%s",
+                       j->unit->id, job_type_to_string(j->type),
+                       j->unit->id, job_type_to_string(newtype));
 
         j->type = newtype;
 }
@@ -549,17 +561,74 @@ int job_run_and_invalidate(Job *j) {
         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.";
+        }
+
+        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);
 
-                format = format_table->finished_start_job[result];
+        if (t == JOB_START) {
+                format = job_get_status_message_format(u, t, result);
                 if (!format)
                         return;
 
@@ -572,7 +641,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
 
                 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:
@@ -587,9 +656,9 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                         ;
                 }
 
-        } else if (t == JOB_STOP) {
+        } 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;
 
@@ -607,9 +676,69 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                 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_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                           u->id,
+                           MESSAGE_ID(mid),
+                           "RESULT=%s", job_result_to_string(result),
+                           "MESSAGE=%s", buf,
+                           NULL);
+
+        } else if (t == JOB_STOP)
+                log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                           u->id,
+                           MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
+                           "RESULT=%s", job_result_to_string(result),
+                           "MESSAGE=%s", buf,
+                           NULL);
+
+        else if (t == JOB_RELOAD)
+                log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                           u->id,
+                           MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
+                           "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;
@@ -625,9 +754,11 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
 
         j->result = result;
 
-        log_debug("Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
+        log_debug_unit(u->id, "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);
 
@@ -684,14 +815,19 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
         }
 
         /* Trigger OnFailure dependencies that are not generated by
-         * the unit itself. We don't tread JOB_CANCELED as failure in
+         * 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) {
-                log_notice("Job %s/%s failed with result '%s'.",
+                log_struct_unit(LOG_NOTICE,
+                           u->id,
+                           "JOB_TYPE=%s", job_type_to_string(t),
+                           "JOB_RESULT=%s", job_result_to_string(result),
+                           "Job %s/%s failed with result '%s'.",
                            u->id,
                            job_type_to_string(t),
-                           job_result_to_string(result));
+                           job_result_to_string(result),
+                           NULL);
 
                 unit_trigger_on_failure(u);
         }
@@ -798,7 +934,8 @@ void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
         assert(j);
         assert(w == &j->timer_watch);
 
-        log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
+        log_warning_unit(j->unit->id, "Job %s/%s timed out.",
+                         j->unit->id, job_type_to_string(j->type));
         job_finish_and_invalidate(j, JOB_TIMEOUT, true);
 }