chiark / gitweb /
Fix possible lack of status messages on shutdown/reboot
[elogind.git] / src / core / job.c
index 990607f990d9eaffcb175e0e358a210c0111f5e1..0dd161c1c58104313214d6b01c2bef7fca019276 100644 (file)
@@ -35,7 +35,7 @@
 #include "log.h"
 #include "dbus-job.h"
 #include "special.h"
-#include "sync.h"
+#include "async.h"
 #include "virt.h"
 
 JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) {
@@ -99,10 +99,10 @@ void job_free(Job *j) {
         assert(!j->object_list);
 
         if (j->in_run_queue)
-                LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
+                LIST_REMOVE(run_queue, j->manager->run_queue, j);
 
         if (j->in_dbus_queue)
-                LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
+                LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
 
         if (j->timer_watch.type != WATCH_INVALID) {
                 assert(j->timer_watch.type == WATCH_JOB_TIMER);
@@ -114,7 +114,7 @@ void job_free(Job *j) {
         }
 
         while ((cl = j->bus_client_list)) {
-                LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
+                LIST_REMOVE(client, j->bus_client_list, cl);
                 free(cl);
         }
         free(j);
@@ -206,6 +206,7 @@ Job* job_install(Job *j) {
                                                "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;
+                                uj->manager->n_running_jobs--;
                                 return uj;
                         }
                 }
@@ -266,9 +267,9 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool
         l->conflicts = conflicts;
 
         if (subject)
-                LIST_PREPEND(JobDependency, subject, subject->subject_list, l);
+                LIST_PREPEND(subject, subject->subject_list, l);
 
-        LIST_PREPEND(JobDependency, object, object->object_list, l);
+        LIST_PREPEND(object, object->object_list, l);
 
         return l;
 }
@@ -277,9 +278,9 @@ void job_dependency_free(JobDependency *l) {
         assert(l);
 
         if (l->subject)
-                LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
+                LIST_REMOVE(subject, l->subject->subject_list, l);
 
-        LIST_REMOVE(JobDependency, object, l->object->object_list, l);
+        LIST_REMOVE(object, l->object->object_list, l);
 
         free(l);
 }
@@ -415,7 +416,7 @@ int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
         return 0;
 }
 
-bool job_is_runnable(Job *j) {
+static bool job_is_runnable(Job *j) {
         Iterator i;
         Unit *other;
 
@@ -483,14 +484,14 @@ static void job_change_type(Job *j, JobType newtype) {
 int job_run_and_invalidate(Job *j) {
         int r;
         uint32_t id;
-        Manager *m;
+        Manager *m = j->manager;
 
         assert(j);
         assert(j->installed);
         assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
         assert(j->in_run_queue);
 
-        LIST_REMOVE(Job, run_queue, j->manager->run_queue, j);
+        LIST_REMOVE(run_queue, j->manager->run_queue, j);
         j->in_run_queue = false;
 
         if (j->state != JOB_WAITING)
@@ -500,6 +501,7 @@ int job_run_and_invalidate(Job *j) {
                 return -EAGAIN;
 
         j->state = JOB_RUNNING;
+        m->n_running_jobs++;
         job_add_to_dbus_queue(j);
 
         /* While we execute this operation the job might go away (for
@@ -508,7 +510,6 @@ int job_run_and_invalidate(Job *j) {
          * store the id here, so that we can verify the job is still
          * valid. */
         id = j->id;
-        m = j->manager;
 
         switch (j->type) {
 
@@ -558,16 +559,17 @@ int job_run_and_invalidate(Job *j) {
                         r = job_finish_and_invalidate(j, JOB_DONE, true);
                 else if (r == -ENOEXEC)
                         r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
-                else if (r == -EAGAIN)
+                else if (r == -EAGAIN) {
                         j->state = JOB_WAITING;
-                else if (r < 0)
+                        m->n_running_jobs--;
+                } else if (r < 0)
                         r = job_finish_and_invalidate(j, JOB_FAILED, true);
         }
 
         return r;
 }
 
-static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
+_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
         const UnitStatusMessageFormats *format_table;
 
         assert(u);
@@ -586,7 +588,7 @@ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult r
         return NULL;
 }
 
-static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
+_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
         const char *format;
 
         assert(u);
@@ -642,20 +644,20 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
 
                 case JOB_DONE:
                         if (u->condition_result)
-                                unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                                unit_status_printf(u, ANSI_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 case JOB_FAILED:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
-                        unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
+                        manager_status_printf(u->manager, false, NULL, "See 'systemctl status %s' for details.", u->id);
                         break;
 
                 case JOB_DEPENDENCY:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 case JOB_TIMEOUT:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 default:
@@ -671,12 +673,12 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                 switch (result) {
 
                 case JOB_TIMEOUT:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 case JOB_DONE:
                 case JOB_FAILED:
-                        unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
+                        unit_status_printf(u, ANSI_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format);
                         break;
 
                 default:
@@ -689,7 +691,7 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
                  * 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));
+                        unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
         }
 }
 
@@ -760,6 +762,9 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
 
         j->result = result;
 
+        if (j->state == JOB_RUNNING)
+                j->manager->n_running_jobs--;
+
         log_debug_unit(u->id, "Job %s/%s finished, result=%s",
                        u->id, job_type_to_string(t), job_result_to_string(result));
 
@@ -835,9 +840,11 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
                            job_result_to_string(result),
                            NULL);
 
-                unit_trigger_on_failure(u);
+                unit_start_on_failure(u);
         }
 
+        unit_trigger_notify(u);
+
 finish:
         /* Try to start the next jobs that can be started */
         SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
@@ -853,10 +860,12 @@ finish:
 }
 
 int job_start_timer(Job *j) {
-        struct itimerspec its;
-        struct epoll_event ev;
+        struct itimerspec its = {};
+        struct epoll_event ev = {
+                .data.ptr = &j->timer_watch,
+                .events = EPOLLIN,
+        };
         int fd, r;
-        assert(j);
 
         if (j->unit->job_timeout <= 0 ||
             j->timer_watch.type == WATCH_JOB_TIMER)
@@ -869,7 +878,6 @@ int job_start_timer(Job *j) {
                 goto fail;
         }
 
-        zero(its);
         timespec_store(&its.it_value, j->unit->job_timeout);
 
         if (timerfd_settime(fd, 0, &its, NULL) < 0) {
@@ -877,10 +885,6 @@ int job_start_timer(Job *j) {
                 goto fail;
         }
 
-        zero(ev);
-        ev.data.ptr = &j->timer_watch;
-        ev.events = EPOLLIN;
-
         if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
                 r = -errno;
                 goto fail;
@@ -906,7 +910,7 @@ void job_add_to_run_queue(Job *j) {
         if (j->in_run_queue)
                 return;
 
-        LIST_PREPEND(Job, run_queue, j->manager->run_queue, j);
+        LIST_PREPEND(run_queue, j->manager->run_queue, j);
         j->in_run_queue = true;
 }
 
@@ -921,7 +925,7 @@ void job_add_to_dbus_queue(Job *j) {
          * job might just have been created and not yet assigned to a
          * connection/client. */
 
-        LIST_PREPEND(Job, dbus_queue, j->manager->dbus_job_queue, j);
+        LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j);
         j->in_dbus_queue = true;
 }
 
@@ -1059,15 +1063,14 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
 }
 
 int job_coldplug(Job *j) {
-        struct epoll_event ev;
+        struct epoll_event ev = {
+                .data.ptr = &j->timer_watch,
+                .events = EPOLLIN,
+        };
 
         if (j->timer_watch.type != WATCH_JOB_TIMER)
                 return 0;
 
-        zero(ev);
-        ev.data.ptr = &j->timer_watch;
-        ev.events = EPOLLIN;
-
         if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, j->timer_watch.fd, &ev) < 0)
                 return -errno;
 
@@ -1085,12 +1088,18 @@ void job_shutdown_magic(Job *j) {
          * asynchronous sync() would cause their exit to be
          * delayed. */
 
-        if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
+        if (j->type != JOB_START)
                 return;
 
-        if (j->type != JOB_START)
+        if (j->unit->manager->running_as != SYSTEMD_SYSTEM)
+                return;
+
+        if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
                 return;
 
+        /* In case messages on console has been disabled on boot */
+        j->unit->manager->no_console_output = false;
+
         if (detect_container(NULL) > 0)
                 return;