chiark / gitweb /
manager: when we immediately reboot due to 7x C-A-D within 2s, mention this on the...
[elogind.git] / src / core / manager.c
index 491809112611af2a495e3a20b4a8e3314321a3db..d86fdd2a0125625c1e1bf3f59a4f3951806c262f 100644 (file)
 #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);
 static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
 static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
 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) {
         usec_t next;
@@ -550,6 +549,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;
@@ -706,7 +708,7 @@ static int manager_setup_kdbus(Manager *m) {
         if (m->test_run || m->kdbus_fd >= 0)
                 return 0;
 
-        if (getpid() == 1)
+        if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
                 bus_kernel_fix_attach_mask();
 
         m->kdbus_fd = bus_kernel_create_bus(
@@ -1086,8 +1088,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         assert(m);
 
         dual_timestamp_get(&m->generators_start_timestamp);
-        manager_run_generators(m);
+        r = manager_run_generators(m);
         dual_timestamp_get(&m->generators_finish_timestamp);
+        if (r < 0)
+                return r;
 
         r = lookup_paths_init(
                         &m->lookup_paths, m->running_as, true,
@@ -1517,8 +1521,6 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
 
                         return -errno;
                 }
-                if (n == 0)
-                        return -ECONNRESET;
 
                 for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
                         if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
@@ -1722,7 +1724,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 too 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;
                         }
 
@@ -2211,7 +2225,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
 
         m->n_reloading ++;
 
-        fprintf(f, "current-job-id=%i\n", m->current_job_id);
+        fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id);
         fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
         fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs);
         fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs);
@@ -2517,7 +2531,9 @@ int manager_reload(Manager *m) {
         lookup_paths_free(&m->lookup_paths);
 
         /* Find new unit paths */
-        manager_run_generators(m);
+        q = manager_run_generators(m);
+        if (q < 0 && r >= 0)
+                r = q;
 
         q = lookup_paths_init(
                         &m->lookup_paths, m->running_as, true,
@@ -2525,19 +2541,19 @@ int manager_reload(Manager *m) {
                         m->generator_unit_path,
                         m->generator_unit_path_early,
                         m->generator_unit_path_late);
-        if (q < 0)
+        if (q < 0 && r >= 0)
                 r = q;
 
         manager_build_unit_path_cache(m);
 
         /* First, enumerate what we can from all config files */
         q = manager_enumerate(m);
-        if (q < 0)
+        if (q < 0 && r >= 0)
                 r = q;
 
         /* Second, deserialize our stored data */
         q = manager_deserialize(m, f, fds);
-        if (q < 0)
+        if (q < 0 && r >= 0)
                 r = q;
 
         fclose(f);
@@ -2545,12 +2561,12 @@ int manager_reload(Manager *m) {
 
         /* Re-register notify_fd as event source */
         q = manager_setup_notify(m);
-        if (q < 0)
+        if (q < 0 && r >= 0)
                 r = q;
 
         /* Third, fire things up! */
         q = manager_coldplug(m);
-        if (q < 0)
+        if (q < 0 && r >= 0)
                 r = q;
 
         assert(m->n_reloading > 0);
@@ -2775,27 +2791,33 @@ static void trim_generator_dir(Manager *m, char **generator) {
         return;
 }
 
-void manager_run_generators(Manager *m) {
-        const char *generator_path;
+static int manager_run_generators(Manager *m) {
+        _cleanup_free_ char **paths = NULL;
         const char *argv[5];
+        char **path;
         int r;
 
         assert(m);
 
         if (m->test_run)
-                return;
+                return 0;
 
-        generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
+        paths = generator_paths(m->running_as);
+        if (!paths)
+                return log_oom();
 
         /* Optimize by skipping the whole process by not creating output directories
          * if no generators are found. */
-        if (access(generator_path, F_OK) != 0) {
+        STRV_FOREACH(path, paths) {
+                r = access(*path, F_OK);
+                if (r == 0)
+                        goto found;
                 if (errno != ENOENT)
-                        log_error_errno(errno, "Failed to open generator directory %s: %m",
-                                        generator_path);
-                return;
+                        log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
         }
+        return 0;
 
+ found:
         r = create_generator_dir(m, &m->generator_unit_path, "generator");
         if (r < 0)
                 goto finish;
@@ -2815,12 +2837,13 @@ void manager_run_generators(Manager *m) {
         argv[4] = NULL;
 
         RUN_WITH_UMASK(0022)
-                execute_directory(generator_path, DEFAULT_TIMEOUT_USEC, (char**) argv);
+                execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
 
 finish:
         trim_generator_dir(m, &m->generator_unit_path);
         trim_generator_dir(m, &m->generator_unit_path_early);
         trim_generator_dir(m, &m->generator_unit_path_late);
+        return r;
 }
 
 static void remove_generator_dir(Manager *m, char **generator) {
@@ -2837,7 +2860,7 @@ static void remove_generator_dir(Manager *m, char **generator) {
         *generator = NULL;
 }
 
-void manager_undo_generators(Manager *m) {
+static void manager_undo_generators(Manager *m) {
         assert(m);
 
         remove_generator_dir(m, &m->generator_unit_path);