chiark / gitweb /
manager: parse RD_TIMESTAMP passed from initrd
[elogind.git] / src / manager.c
index 26a631e9d7fc0db7807d8a18211da0a353cb1e0d..d690a0f16bca0dbfd091ff7f1294dd6a526fae8b 100644 (file)
@@ -164,11 +164,16 @@ static int manager_setup_signals(Manager *m) {
                         SIGWINCH,    /* Kernel sends us this on kbrequest (alt-arrowup) */
                         SIGPWR,      /* Some kernel drivers and upsd send us this on power failure */
                         SIGRTMIN+0,  /* systemd: start default.target */
-                        SIGRTMIN+1,  /* systemd: start rescue.target */
+                        SIGRTMIN+1,  /* systemd: isolate rescue.target */
                         SIGRTMIN+2,  /* systemd: isolate emergency.target */
                         SIGRTMIN+3,  /* systemd: start halt.target */
                         SIGRTMIN+4,  /* systemd: start poweroff.target */
                         SIGRTMIN+5,  /* systemd: start reboot.target */
+                        SIGRTMIN+6,  /* systemd: start kexec.target */
+                        SIGRTMIN+13, /* systemd: Immediate halt */
+                        SIGRTMIN+14, /* systemd: Immediate poweroff */
+                        SIGRTMIN+15, /* systemd: Immediate reboot */
+                        SIGRTMIN+16, /* systemd: Immediate kexec */
                         -1);
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
@@ -211,7 +216,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         m->audit_fd = -1;
 #endif
 
-        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
+        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
         m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
 
         if (!(m->environment = strv_copy(environ)))
@@ -1128,7 +1133,8 @@ static void transaction_minimize_impact(Manager *m) {
                                         j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
 
                                 changes_existing_job =
-                                        j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->type);
+                                        j->unit->meta.job &&
+                                        job_type_is_conflicting(j->type, j->unit->meta.job->type);
 
                                 if (!stops_running_service && !changes_existing_job)
                                         continue;
@@ -1193,6 +1199,8 @@ static int transaction_apply(Manager *m) {
                 job_add_to_run_queue(j);
                 job_add_to_dbus_queue(j);
                 job_start_timer(j);
+
+                log_debug("Installed new job %s/%s as %u", j->unit->meta.id, job_type_to_string(j->type), (unsigned) j->id);
         }
 
         /* As last step, kill all remaining job dependencies. */
@@ -1227,7 +1235,7 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
         /* Second step: Try not to stop any running services if
          * we don't have to. Don't try to reverse running
          * jobs if we don't have to. */
-        if (mode != JOB_ISOLATE)
+        if (mode == JOB_FAIL)
                 transaction_minimize_impact(m);
 
         /* Third step: Drop redundant jobs */
@@ -1400,7 +1408,7 @@ static int transaction_add_job_and_dependencies(
 
         if (unit->meta.load_state != UNIT_LOADED &&
             unit->meta.load_state != UNIT_ERROR &&
-            unit->meta.load_state != UNIT_BANNED) {
+            unit->meta.load_state != UNIT_MASKED) {
                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->meta.id);
                 return -EINVAL;
         }
@@ -1408,14 +1416,14 @@ static int transaction_add_job_and_dependencies(
         if (type != JOB_STOP && unit->meta.load_state == UNIT_ERROR) {
                 dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
                                "Unit %s failed to load: %s. "
-                               "You might find more information in the system logs.",
+                               "See system logs and 'systemctl status' for details.",
                                unit->meta.id,
                                strerror(-unit->meta.load_error));
                 return -EINVAL;
         }
 
-        if (type != JOB_STOP && unit->meta.load_state == UNIT_BANNED) {
-                dbus_set_error(e, BUS_ERROR_BANNED, "Unit %s is banned.", unit->meta.id);
+        if (type != JOB_STOP && unit->meta.load_state == UNIT_MASKED) {
+                dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->meta.id);
                 return -EINVAL;
         }
 
@@ -1439,6 +1447,10 @@ static int transaction_add_job_and_dependencies(
                                 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR)
                                         goto fail;
 
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BIND_TO], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR)
+                                        goto fail;
+
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
                                 if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, e, NULL)) < 0 && r != -EBADR) {
                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
@@ -1472,7 +1484,7 @@ static int transaction_add_job_and_dependencies(
                                         goto fail;
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTED_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, e, NULL)) < 0 && r != -EBADR)
                                         goto fail;
 
                 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
@@ -1480,6 +1492,10 @@ static int transaction_add_job_and_dependencies(
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
                                 if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR)
                                         goto fail;
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BOUND_BY], i)
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR)
+                                        goto fail;
                 }
 
                 /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
@@ -1512,7 +1528,7 @@ static int transaction_add_isolate_jobs(Manager *m) {
                         continue;
 
                 /* No need to stop inactive jobs */
-                if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)))
+                if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->meta.job)
                         continue;
 
                 /* Is there already something listed for this? */
@@ -1641,7 +1657,7 @@ int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DB
         if (!name)
                 name = file_name_from_path(path);
 
-        if (!unit_name_is_valid(name)) {
+        if (!unit_name_is_valid(name, false)) {
                 dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
                 return -EINVAL;
         }
@@ -1987,7 +2003,7 @@ static int manager_process_signal_fd(Manager *m) {
                         }
 
                         /* Run the exit target if there is one, if not, just exit. */
-                        if (manager_start_target(m, SPECIAL_EXIT_SERVICE, JOB_REPLACE) < 0) {
+                        if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
                                 m->exit_code = MANAGER_EXIT;
                                 return 0;
                         }
@@ -2058,22 +2074,38 @@ static int manager_process_signal_fd(Manager *m) {
                         break;
 
                 default: {
-                        static const char * const table[] = {
+                        /* Starting SIGRTMIN+0 */
+                        static const char * const target_table[] = {
                                 [0] = SPECIAL_DEFAULT_TARGET,
                                 [1] = SPECIAL_RESCUE_TARGET,
                                 [2] = SPECIAL_EMERGENCY_TARGET,
                                 [3] = SPECIAL_HALT_TARGET,
                                 [4] = SPECIAL_POWEROFF_TARGET,
-                                [5] = SPECIAL_REBOOT_TARGET
+                                [5] = SPECIAL_REBOOT_TARGET,
+                                [6] = SPECIAL_KEXEC_TARGET
+                        };
+
+                        /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
+                        static const ManagerExitCode code_table[] = {
+                                [0] = MANAGER_HALT,
+                                [1] = MANAGER_POWEROFF,
+                                [2] = MANAGER_REBOOT,
+                                [3] = MANAGER_KEXEC
                         };
 
                         if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
-                            (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(table)) {
-                                manager_start_target(m, table[sfsi.ssi_signo - SIGRTMIN],
+                            (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
+                                manager_start_target(m, target_table[sfsi.ssi_signo - SIGRTMIN],
                                                      (sfsi.ssi_signo == 1 || sfsi.ssi_signo == 2) ? JOB_ISOLATE : JOB_REPLACE);
                                 break;
                         }
 
+                        if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
+                            (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
+                                m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
+                                break;
+                        }
+
                         log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo)));
                 }
                 }
@@ -2150,6 +2182,11 @@ static int process_event(Manager *m, struct epoll_event *ev) {
                 mount_fd_event(m, ev->events);
                 break;
 
+        case WATCH_SWAP:
+                /* Some swap table change, intended for the swap subsystem */
+                swap_fd_event(m, ev->events);
+                break;
+
         case WATCH_UDEV:
                 /* Some notification from udev, intended for the device subsystem */
                 device_fd_event(m, ev->events);
@@ -2217,6 +2254,9 @@ int manager_loop(Manager *m) {
                 if (manager_dispatch_dbus_queue(m) > 0)
                         continue;
 
+                if (swap_dispatch_reload(m) > 0)
+                        continue;
+
                 if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
 
                         if (errno == EINTR)
@@ -2461,9 +2501,11 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
         assert(f);
         assert(fds);
 
-        fprintf(f, "startup-timestamp=%llu %llu\n\n",
-                (unsigned long long) m->startup_timestamp.realtime,
-                (unsigned long long) m->startup_timestamp.monotonic);
+        dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
+        dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp);
+        dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
+
+        fputc('\n', f);
 
         HASHMAP_FOREACH_KEY(u, t, m->units, i) {
                 if (u->meta.id != t)
@@ -2514,16 +2556,13 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                 if (l[0] == 0)
                         break;
 
-                if (startswith(l, "startup-timestamp=")) {
-                        unsigned long long a, b;
-
-                        if (sscanf(l+18, "%lli %llu", &a, &b) != 2)
-                                log_debug("Failed to parse startup timestamp value %s", l+18);
-                        else {
-                                m->startup_timestamp.realtime = a;
-                                m->startup_timestamp.monotonic = b;
-                        }
-                } else
+                if (startswith(l, "initrd-timestamp="))
+                        dual_timestamp_deserialize(l+17, &m->initrd_timestamp);
+                else if (startswith(l, "startup-timestamp="))
+                        dual_timestamp_deserialize(l+18, &m->startup_timestamp);
+                else if (startswith(l, "finish-timestamp="))
+                        dual_timestamp_deserialize(l+17, &m->finish_timestamp);
+                else
                         log_debug("Unknown serialization item '%s'", l);
         }
 
@@ -2679,7 +2718,7 @@ bool manager_unit_pending_inactive(Manager *m, const char *name) {
 }
 
 void manager_check_finished(Manager *m) {
-        char userspace[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
+        char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
 
         assert(m);
 
@@ -2691,15 +2730,26 @@ void manager_check_finished(Manager *m) {
 
         dual_timestamp_get(&m->finish_timestamp);
 
-        if (m->running_as == MANAGER_SYSTEM)
-                log_info("Startup finished in %s (kernel) + %s (userspace) = %s.",
-                         format_timespan(kernel, sizeof(kernel),
-                                         m->startup_timestamp.monotonic),
-                         format_timespan(userspace, sizeof(userspace),
-                                         m->finish_timestamp.monotonic - m->startup_timestamp.monotonic),
-                         format_timespan(sum, sizeof(sum),
-                                         m->finish_timestamp.monotonic));
-        else
+        if (m->running_as == MANAGER_SYSTEM) {
+                if (dual_timestamp_is_set(&m->initrd_timestamp)) {
+                        log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
+                                 format_timespan(kernel, sizeof(kernel),
+                                                 m->initrd_timestamp.monotonic),
+                                 format_timespan(initrd, sizeof(initrd),
+                                                 m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic),
+                                 format_timespan(userspace, sizeof(userspace),
+                                                 m->finish_timestamp.monotonic - m->startup_timestamp.monotonic),
+                                 format_timespan(sum, sizeof(sum),
+                                                 m->finish_timestamp.monotonic));
+                } else
+                        log_info("Startup finished in %s (kernel) + %s (userspace) = %s.",
+                                 format_timespan(kernel, sizeof(kernel),
+                                                 m->startup_timestamp.monotonic),
+                                 format_timespan(userspace, sizeof(userspace),
+                                                 m->finish_timestamp.monotonic - m->startup_timestamp.monotonic),
+                                 format_timespan(sum, sizeof(sum),
+                                                 m->finish_timestamp.monotonic));
+        } else
                 log_debug("Startup finished in %s.",
                           format_timespan(userspace, sizeof(userspace),
                                           m->finish_timestamp.monotonic - m->startup_timestamp.monotonic));