chiark / gitweb /
util: replace close_nointr_nofail() by a more useful safe_close()
[elogind.git] / src / core / manager.c
index 27a1cc6777eaf2be55821236f9355b4a99edff93..632ce74ac29b291a10e6bbf66bf257c5b446f582 100644 (file)
@@ -140,6 +140,8 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
 }
 
 void manager_flip_auto_status(Manager *m, bool enable) {
+        assert(m);
+
         if (enable) {
                 if (m->show_status == SHOW_STATUS_AUTO)
                         manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
@@ -248,8 +250,7 @@ static int manager_setup_time_change(Manager *m) {
 
         if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
                 log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
-                close_nointr_nofail(m->time_change_fd);
-                m->time_change_fd = -1;
+                m->time_change_fd = safe_close(m->time_change_fd);
                 return 0;
         }
 
@@ -451,6 +452,10 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
         if (r < 0)
                 goto fail;
 
+        r = set_ensure_allocated(&m->failed_units, trivial_hash_func, trivial_compare_func);
+        if (r < 0)
+                goto fail;
+
         r = sd_event_default(&m->event);
         if (r < 0)
                 goto fail;
@@ -778,6 +783,8 @@ void manager_free(Manager *m) {
         hashmap_free(m->watch_pids2);
         hashmap_free(m->watch_bus);
 
+        set_free(m->failed_units);
+
         sd_event_source_unref(m->signal_event_source);
         sd_event_source_unref(m->notify_event_source);
         sd_event_source_unref(m->time_change_event_source);
@@ -785,14 +792,10 @@ void manager_free(Manager *m) {
         sd_event_source_unref(m->idle_pipe_event_source);
         sd_event_source_unref(m->run_queue_event_source);
 
-        if (m->signal_fd >= 0)
-                close_nointr_nofail(m->signal_fd);
-        if (m->notify_fd >= 0)
-                close_nointr_nofail(m->notify_fd);
-        if (m->time_change_fd >= 0)
-                close_nointr_nofail(m->time_change_fd);
-        if (m->kdbus_fd >= 0)
-                close_nointr_nofail(m->kdbus_fd);
+        safe_close(m->signal_fd);
+        safe_close(m->notify_fd);
+        safe_close(m->time_change_fd);
+        safe_close(m->kdbus_fd);
 
         manager_close_idle_pipe(m);
 
@@ -1621,6 +1624,11 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
                                 break;
                         }
 
+                        if (fflush(f)) {
+                                log_warning("Failed to flush status stream");
+                                break;
+                        }
+
                         log_dump(LOG_INFO, dump);
                         break;
                 }
@@ -1743,9 +1751,7 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
 
         /* Restart the watch */
         m->time_change_event_source = sd_event_source_unref(m->time_change_event_source);
-
-        close_nointr_nofail(m->time_change_fd);
-        m->time_change_fd = -1;
+        m->time_change_fd = safe_close(m->time_change_fd);
 
         manager_setup_time_change(m);
 
@@ -1794,7 +1800,7 @@ int manager_loop(Manager *m) {
         RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
 
         assert(m);
-        m->exit_code = MANAGER_RUNNING;
+        m->exit_code = MANAGER_OK;
 
         /* Release the path cache */
         set_free_free(m->unit_path_cache);
@@ -1808,7 +1814,7 @@ int manager_loop(Manager *m) {
         if (r < 0)
                 return r;
 
-        while (m->exit_code == MANAGER_RUNNING) {
+        while (m->exit_code == MANAGER_OK) {
                 usec_t wait_usec;
 
                 if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
@@ -2029,7 +2035,7 @@ int manager_open_serialization(Manager *m, FILE **_f) {
 
         f = fdopen(fd, "w+");
         if (!f) {
-                close_nointr_nofail(fd);
+                safe_close(fd);
                 return -errno;
         }
 
@@ -2250,11 +2256,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
                                 log_debug("Failed to parse notify fd: %s", l + 10);
                         else {
-                                if (m->notify_fd >= 0) {
-                                        m->notify_event_source = sd_event_source_unref(m->notify_event_source);
-                                        close_nointr_nofail(m->notify_fd);
-                                }
-
+                                m->notify_event_source = sd_event_source_unref(m->notify_event_source);
+                                safe_close(m->notify_fd);
                                 m->notify_fd = fdset_remove(fds, fd);
                         }
 
@@ -2276,9 +2279,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
                                 log_debug("Failed to parse kdbus fd: %s", l + 9);
                         else {
-                                if (m->kdbus_fd >= 0)
-                                        close_nointr_nofail(m->kdbus_fd);
-
+                                safe_close(m->kdbus_fd);
                                 m->kdbus_fd = fdset_remove(fds, fd);
                         }
 
@@ -2401,23 +2402,6 @@ int manager_reload(Manager *m) {
         return r;
 }
 
-static bool manager_is_booting_or_shutting_down(Manager *m) {
-        Unit *u;
-
-        assert(m);
-
-        /* Is the initial job still around? */
-        if (manager_get_job(m, m->default_unit_job_id))
-                return true;
-
-        /* Is there a job for the shutdown target? */
-        u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
-        if (u)
-                return !!u->job;
-
-        return false;
-}
-
 bool manager_is_reloading_or_reexecuting(Manager *m) {
         assert(m);
 
@@ -2458,10 +2442,12 @@ void manager_check_finished(Manager *m) {
                 m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source);
 
         if (hashmap_size(m->jobs) > 0) {
+
                 if (m->jobs_in_progress_event_source) {
-                        uint64_t next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
-                        sd_event_source_set_time(m->jobs_in_progress_event_source, next);
+                        sd_event_source_set_time(m->jobs_in_progress_event_source,
+                                                 now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
                 }
+
                 return;
         }
 
@@ -2789,6 +2775,9 @@ static bool manager_get_show_status(Manager *m) {
         if (m->no_console_output)
                 return false;
 
+        if (!IN_SET(manager_state(m), MANAGER_STARTING, MANAGER_STOPPING))
+                return false;
+
         if (m->show_status > 0)
                 return true;
 
@@ -2809,9 +2798,6 @@ void manager_status_printf(Manager *m, bool ephemeral, const char *status, const
         if (ephemeral && m->n_on_console > 0)
                 return;
 
-        if (!manager_is_booting_or_shutting_down(m))
-                return;
-
         va_start(ap, format);
         status_vprintf(status, true, ephemeral, format, ap);
         va_end(ap);
@@ -2853,8 +2839,51 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
 }
 
 const char *manager_get_runtime_prefix(Manager *m) {
+        assert(m);
 
         return m->running_as == SYSTEMD_SYSTEM ?
                "/run" :
                getenv("XDG_RUNTIME_DIR");
 }
+
+ManagerState manager_state(Manager *m) {
+        Unit *u;
+
+        assert(m);
+
+        /* Did we ever finish booting? If not then we are still starting up */
+        if (!dual_timestamp_is_set(&m->finish_timestamp))
+                return MANAGER_STARTING;
+
+        /* Is the special shutdown target queued? If so, we are in shutdown state */
+        u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
+        if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))
+                return MANAGER_STOPPING;
+
+        /* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
+        u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
+        if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
+                  (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
+                return MANAGER_MAINTENANCE;
+
+        u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
+        if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
+                  (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
+                return MANAGER_MAINTENANCE;
+
+        /* Are there any failed units? If so, we are in degraded mode */
+        if (set_size(m->failed_units) > 0)
+                return MANAGER_DEGRADED;
+
+        return MANAGER_RUNNING;
+}
+
+static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
+        [MANAGER_STARTING] = "starting",
+        [MANAGER_RUNNING] = "running",
+        [MANAGER_DEGRADED] = "degraded",
+        [MANAGER_MAINTENANCE] = "maintenance",
+        [MANAGER_STOPPING] = "stopping",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);