chiark / gitweb /
core: do not use quotes around virt and arch
[elogind.git] / src / core / manager.c
index 4f771396a0ceb5fb59cbc8e49415b58e3567e4eb..d92e048e2468cf61ababfd9d4c310d305b3d6315 100644 (file)
@@ -19,7 +19,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
 #include <unistd.h>
 #include <sys/inotify.h>
 #include <sys/epoll.h>
-#include <sys/poll.h>
 #include <sys/reboot.h>
 #include <sys/ioctl.h>
 #include <linux/kd.h>
-#include <termios.h>
 #include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <dirent.h>
 #include <sys/timerfd.h>
 
@@ -43,7 +38,6 @@
 #endif
 
 #include "sd-daemon.h"
-#include "sd-id128.h"
 #include "sd-messages.h"
 
 #include "manager.h"
@@ -56,7 +50,6 @@
 #include "mkdir.h"
 #include "ratelimit.h"
 #include "locale-setup.h"
-#include "mount-setup.h"
 #include "unit-name.h"
 #include "missing.h"
 #include "path-lookup.h"
@@ -64,7 +57,6 @@
 #include "exit-status.h"
 #include "virt.h"
 #include "watchdog.h"
-#include "cgroup-util.h"
 #include "path-util.h"
 #include "audit-fd.h"
 #include "boot-timestamps.h"
@@ -84,9 +76,6 @@
 #define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
 #define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
 
-#define NOTIFY_FD_MAX 768
-#define NOTIFY_BUFFER_MAX PIPE_BUF
-
 static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
 static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
 static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
@@ -96,16 +85,16 @@ static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
 static int manager_run_generators(Manager *m);
 static void manager_undo_generators(Manager *m);
 
-static int manager_watch_jobs_in_progress(Manager *m) {
+static void manager_watch_jobs_in_progress(Manager *m) {
         usec_t next;
 
         assert(m);
 
         if (m->jobs_in_progress_event_source)
-                return 0;
+                return;
 
         next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
-        return sd_event_add_time(
+        (void) sd_event_add_time(
                         m->event,
                         &m->jobs_in_progress_event_source,
                         CLOCK_MONOTONIC,
@@ -189,8 +178,10 @@ static void manager_print_jobs_in_progress(Manager *m) {
 
         m->jobs_in_progress_iteration++;
 
-        if (m->n_running_jobs > 1)
-                asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs);
+        if (m->n_running_jobs > 1) {
+                if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
+                        job_of_n = NULL;
+        }
 
         format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
         if (job_get_timeout(j, &x) > 0)
@@ -552,6 +543,9 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
 
         m->test_run = test_run;
 
+        /* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
+        RATELIMIT_INIT(m->ctrl_alt_del_ratelimit, 2 * USEC_PER_SEC, 7);
+
         r = manager_default_environment(m);
         if (r < 0)
                 goto fail;
@@ -961,7 +955,7 @@ int manager_enumerate(Manager *m) {
                 int q;
 
                 if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
-                        log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c));
+                        log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
                         continue;
                 }
 
@@ -983,7 +977,28 @@ static int manager_coldplug(Manager *m) {
         Unit *u;
         char *k;
 
-        assert(m);
+        /*
+         * Some unit types tend to spawn jobs or check other units' state
+         * during coldplug. This is wrong because it is undefined whether the
+         * units in question have been already coldplugged (i. e. their state
+         * restored). This way, we can easily re-start an already started unit
+         * or otherwise make a wrong decision based on the unit's state.
+         *
+         * Solve this by providing a way for coldplug functions to defer
+         * such actions until after all units have been coldplugged.
+         *
+         * We store Unit* -> int(*)(Unit*).
+         *
+         * https://bugs.freedesktop.org/show_bug.cgi?id=88401
+         */
+        _cleanup_hashmap_free_ Hashmap *deferred_work = NULL;
+        int(*proc)(Unit*);
+
+        assert(m);
+
+        deferred_work = hashmap_new(&trivial_hash_ops);
+        if (!deferred_work)
+                return -ENOMEM;
 
         /* Then, let's set up their initial state. */
         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
@@ -993,7 +1008,17 @@ static int manager_coldplug(Manager *m) {
                 if (u->id != k)
                         continue;
 
-                q = unit_coldplug(u);
+                q = unit_coldplug(u, deferred_work);
+                if (q < 0)
+                        r = q;
+        }
+
+        /* After coldplugging and setting up initial state of the units,
+         * let's perform operations which spawn jobs or query units' state. */
+        HASHMAP_FOREACH_KEY(proc, u, deferred_work, i) {
+                int q;
+
+                q = proc(u);
                 if (q < 0)
                         r = q;
         }
@@ -1724,7 +1749,19 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
 
                 case SIGINT:
                         if (m->running_as == SYSTEMD_SYSTEM) {
-                                manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
+
+                                /* If the user presses C-A-D more than
+                                 * 7 times within 2s, we reboot
+                                 * immediately. */
+
+                                if (ratelimit_test(&m->ctrl_alt_del_ratelimit))
+                                        manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
+                                else {
+                                        log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
+                                        status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
+                                        m->exit_code = MANAGER_REBOOT;
+                                }
+
                                 break;
                         }
 
@@ -2094,8 +2131,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
                 return;
         }
 
-        msg = strappenda("unit=", p);
-
+        msg = strjoina("unit=", p);
         if (audit_log_user_comm_message(audit_fd, type, msg, "systemd", NULL, NULL, NULL, success) < 0) {
                 if (errno == EPERM)
                         /* We aren't allowed to send audit messages?
@@ -2673,7 +2709,9 @@ void manager_check_finished(Manager *m) {
         if (hashmap_size(m->jobs) > 0) {
 
                 if (m->jobs_in_progress_event_source)
-                        sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
+                        /* Ignore any failure, this is only for feedback */
+                        (void) sd_event_source_set_time(m->jobs_in_progress_event_source,
+                                                        now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
 
                 return;
         }
@@ -3050,6 +3088,24 @@ const char *manager_get_runtime_prefix(Manager *m) {
                getenv("XDG_RUNTIME_DIR");
 }
 
+void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
+        unsigned size;
+
+        assert(m);
+        assert(u->manager == m);
+
+        size = set_size(m->failed_units);
+
+        if (failed) {
+                if (set_put(m->failed_units, u) < 0)
+                        log_oom();
+        } else
+                set_remove(m->failed_units, u);
+
+        if (set_size(m->failed_units) != size)
+                bus_manager_send_change_signal(m);
+}
+
 ManagerState manager_state(Manager *m) {
         Unit *u;