chiark / gitweb /
Merge branch 'master' into journal
[elogind.git] / src / manager.c
index 69d231a85f00cc446df7c583b50cacf434f8b737..f8cbcfcc98ff8fa7faf1f25dadf1ec7fa908e5f5 100644 (file)
@@ -58,6 +58,8 @@
 #include "special.h"
 #include "bus-errors.h"
 #include "exit-status.h"
+#include "sd-daemon.h"
+#include "virt.h"
 
 /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
 #define GC_QUEUE_ENTRIES_MAX 16
@@ -75,7 +77,8 @@ static int manager_setup_notify(Manager *m) {
                 struct sockaddr_un un;
         } sa;
         struct epoll_event ev;
-        int one = 1;
+        int one = 1, r;
+        mode_t u;
 
         assert(m);
 
@@ -98,7 +101,11 @@ static int manager_setup_notify(Manager *m) {
         if (sa.un.sun_path[0] == '@')
                 sa.un.sun_path[0] = 0;
 
-        if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+        u = umask(0111);
+        r = bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
+        umask(u);
+
+        if (r < 0) {
                 log_error("bind() failed: %m");
                 return -errno;
         }
@@ -127,7 +134,7 @@ static int manager_setup_notify(Manager *m) {
 }
 
 static int enable_special_signals(Manager *m) {
-        char fd;
+        int fd;
 
         assert(m);
 
@@ -135,7 +142,7 @@ static int enable_special_signals(Manager *m) {
         if (reboot(RB_DISABLE_CAD) < 0)
                 log_warning("Failed to enable ctrl-alt-del handling: %m");
 
-        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0)
+        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
                 log_warning("Failed to open /dev/tty0: %m");
         else {
                 /* Enable that we get SIGWINCH on kbrequest */
@@ -185,6 +192,11 @@ static int manager_setup_signals(Manager *m) {
                         SIGRTMIN+16, /* systemd: Immediate kexec */
                         SIGRTMIN+20, /* systemd: enable status messages */
                         SIGRTMIN+21, /* systemd: disable status messages */
+                        SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
+                        SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
+                        SIGRTMIN+27, /* systemd: set log target to console */
+                        SIGRTMIN+28, /* systemd: set log target to kmsg */
+                        SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */
                         -1);
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
@@ -257,7 +269,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
                 goto fail;
 
-        if ((r = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0)
+        if ((r = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
                 goto fail;
 
         if ((r = manager_setup_signals(m)) < 0)
@@ -274,10 +286,15 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
                 goto fail;
 
 #ifdef HAVE_AUDIT
-        if ((m->audit_fd = audit_open()) < 0)
+        if ((m->audit_fd = audit_open()) < 0 &&
+            /* If the kernel lacks netlink or audit support,
+             * don't worry about it. */
+            errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
                 log_error("Failed to connect to audit log: %m");
 #endif
 
+        m->taint_usr = dir_is_empty("/usr") > 0;
+
         *_m = m;
         return 0;
 
@@ -552,7 +569,8 @@ static void manager_build_unit_path_cache(Manager *m) {
                         if (ignore_file(de->d_name))
                                 continue;
 
-                        if (asprintf(&p, "%s/%s", streq(*i, "/") ? "" : *i, de->d_name) < 0) {
+                        p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
+                        if (!p) {
                                 r = -ENOMEM;
                                 goto fail;
                         }
@@ -592,7 +610,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
          * this is already known, so we increase the counter here
          * already */
         if (serialization)
-                m->n_deserializing ++;
+                m->n_reloading ++;
 
         /* First, enumerate what we can from all config files */
         r = manager_enumerate(m);
@@ -607,8 +625,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
                 r = q;
 
         if (serialization) {
-                assert(m->n_deserializing > 0);
-                m->n_deserializing --;
+                assert(m->n_reloading > 0);
+                m->n_reloading --;
         }
 
         return r;
@@ -894,6 +912,9 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) {
                                 transaction_merge_and_delete_job(m, j, k, t);
                 }
 
+                if (j->unit->meta.job && !j->installed)
+                        transaction_merge_and_delete_job(m, j, j->unit->meta.job, t);
+
                 assert(!j->transaction_next);
                 assert(!j->transaction_prev);
         }
@@ -1165,13 +1186,13 @@ static void transaction_minimize_impact(Manager *m) {
                                         continue;
 
                                 if (stops_running_service)
-                                        log_info("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
+                                        log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
 
                                 if (changes_existing_job)
-                                        log_info("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
+                                        log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
 
                                 /* Ok, let's get rid of this */
-                                log_info("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
+                                log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
 
                                 transaction_delete_job(m, j, true);
                                 again = true;
@@ -1185,13 +1206,32 @@ static void transaction_minimize_impact(Manager *m) {
         } while (again);
 }
 
-static int transaction_apply(Manager *m) {
+static int transaction_apply(Manager *m, JobMode mode) {
         Iterator i;
         Job *j;
         int r;
 
         /* Moves the transaction jobs to the set of active jobs */
 
+        if (mode == JOB_ISOLATE) {
+
+                /* When isolating first kill all installed jobs which
+                 * aren't part of the new transaction */
+        rescan:
+                HASHMAP_FOREACH(j, m->jobs, i) {
+                        assert(j->installed);
+
+                        if (hashmap_get(m->transaction_jobs, j->unit))
+                                continue;
+
+                        /* 'j' itself is safe to remove, but if other jobs
+                           are invalidated recursively, our iterator may become
+                           invalid and we need to start over. */
+                        if (job_finish_and_invalidate(j, JOB_CANCELED) > 0)
+                                goto rescan;
+                }
+        }
+
         HASHMAP_FOREACH(j, m->transaction_jobs, i) {
                 /* Assume merged */
                 assert(!j->transaction_prev);
@@ -1271,7 +1311,8 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
         for (;;) {
                 /* Fourth step: Let's remove unneeded jobs that might
                  * be lurking. */
-                transaction_collect_garbage(m);
+                if (mode != JOB_ISOLATE)
+                        transaction_collect_garbage(m);
 
                 /* Fifth step: verify order makes sense and correct
                  * cycles if necessary and possible */
@@ -1301,7 +1342,8 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
 
                 /* Seventh step: an entry got dropped, let's garbage
                  * collect its dependencies. */
-                transaction_collect_garbage(m);
+                if (mode != JOB_ISOLATE)
+                        transaction_collect_garbage(m);
 
                 /* Let's see if the resulting transaction still has
                  * unmergeable entries ... */
@@ -1318,7 +1360,7 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
                 }
 
         /* Tenth step: apply changes */
-        if ((r = transaction_apply(m)) < 0) {
+        if ((r = transaction_apply(m, mode)) < 0) {
                 log_warning("Failed to apply transaction: %s", strerror(-r));
                 goto rollback;
         }
@@ -1421,7 +1463,8 @@ static int transaction_add_job_and_dependencies(
                 bool matters,
                 bool override,
                 bool conflicts,
-                bool ignore_deps,
+                bool ignore_requirements,
+                bool ignore_order,
                 DBusError *e,
                 Job **_ret) {
         Job *ret;
@@ -1449,9 +1492,10 @@ 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. "
-                               "See system logs and 'systemctl status' for details.",
+                               "See system logs and 'systemctl status %s' for details.",
                                unit->meta.id,
-                               strerror(-unit->meta.load_error));
+                               strerror(-unit->meta.load_error),
+                               unit->meta.id);
                 return -EINVAL;
         }
 
@@ -1469,20 +1513,20 @@ static int transaction_add_job_and_dependencies(
         if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
                 return -ENOMEM;
 
-        ret->ignore_deps = ret->ignore_deps || ignore_deps;
+        ret->ignore_order = ret->ignore_order || ignore_order;
 
         /* Then, add a link to the job. */
         if (!job_dependency_new(by, ret, matters, conflicts))
                 return -ENOMEM;
 
-        if (is_new && !ignore_deps) {
+        if (is_new && !ignore_requirements) {
                 Set *following;
 
                 /* If we are following some other unit, make sure we
                  * add all dependencies of everybody following. */
                 if (unit_following_set(ret->unit, &following) > 0) {
                         SET_FOREACH(dep, following, i)
-                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
 
                                         if (e)
@@ -1495,7 +1539,7 @@ static int transaction_add_job_and_dependencies(
                 /* Finally, recursively add in all dependencies. */
                 if (type == JOB_START || type == JOB_RELOAD_OR_START) {
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
 
@@ -1504,7 +1548,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         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, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
 
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1514,7 +1558,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         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, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
 
                                         if (e)
@@ -1522,7 +1566,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) {
                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
 
                                         if (e)
@@ -1530,7 +1574,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
 
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1540,7 +1584,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
 
                                         if (e)
@@ -1548,7 +1592,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) {
 
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1558,7 +1602,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTED_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
                                         log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
 
                                         if (e)
@@ -1568,7 +1612,7 @@ static int transaction_add_job_and_dependencies(
                 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
 
                         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, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
 
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1578,7 +1622,7 @@ static int transaction_add_job_and_dependencies(
                                 }
 
                         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, false, e, NULL)) < 0) {
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
 
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1614,7 +1658,7 @@ static int transaction_add_isolate_jobs(Manager *m) {
                 if (u->meta.id != k)
                         continue;
 
-                if (UNIT_VTABLE(u)->no_isolate)
+                if (u->meta.ignore_on_isolate)
                         continue;
 
                 /* No need to stop inactive jobs */
@@ -1625,7 +1669,7 @@ static int transaction_add_isolate_jobs(Manager *m) {
                 if (hashmap_get(m->transaction_jobs, u))
                         continue;
 
-                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, NULL, NULL)) < 0)
+                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL)) < 0)
                         log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r));
         }
 
@@ -1653,7 +1697,9 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
 
         log_debug("Trying to enqueue job %s/%s/%s", unit->meta.id, job_type_to_string(type), job_mode_to_string(mode));
 
-        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) {
+        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false,
+                                                      mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
+                                                      mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) {
                 transaction_abort(m);
                 return r;
         }
@@ -1986,7 +2032,7 @@ static int manager_dispatch_sigchld(Manager *m) {
                 if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
                         char *name = NULL;
 
-                        get_process_name(si.si_pid, &name);
+                        get_process_comm(si.si_pid, &name);
                         log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
                         free(name);
                 }
@@ -2057,8 +2103,6 @@ static int manager_process_signal_fd(Manager *m) {
         assert(m);
 
         for (;;) {
-                char *p = NULL;
-
                 if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
 
                         if (n >= 0)
@@ -2070,13 +2114,17 @@ static int manager_process_signal_fd(Manager *m) {
                         return -errno;
                 }
 
-                if (sfsi.ssi_pid > 0)
-                        get_process_name(sfsi.ssi_pid, &p);
+                if (sfsi.ssi_pid > 0) {
+                        char *p = NULL;
 
-                log_debug("Received SIG%s from PID %lu (%s)",
-                          strna(signal_to_string(sfsi.ssi_signo)),
-                          (unsigned long) sfsi.ssi_pid, strna(p));
-                free(p);
+                        get_process_comm(sfsi.ssi_pid, &p);
+
+                        log_debug("Received SIG%s from PID %lu (%s).",
+                                  signal_to_string(sfsi.ssi_signo),
+                                  (unsigned long) sfsi.ssi_pid, strna(p));
+                        free(p);
+                } else
+                        log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo));
 
                 switch (sfsi.ssi_signo) {
 
@@ -2172,6 +2220,7 @@ static int manager_process_signal_fd(Manager *m) {
                         break;
 
                 default: {
+
                         /* Starting SIGRTMIN+0 */
                         static const char * const target_table[] = {
                                 [0] = SPECIAL_DEFAULT_TARGET,
@@ -2193,8 +2242,9 @@ static int manager_process_signal_fd(Manager *m) {
 
                         if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
                             (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);
+                                int idx = (int) sfsi.ssi_signo - SIGRTMIN;
+                                manager_start_target(m, target_table[idx],
+                                                     (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
                                 break;
                         }
 
@@ -2208,16 +2258,41 @@ static int manager_process_signal_fd(Manager *m) {
 
                         case 20:
                                 log_debug("Enabling showing of status.");
-                                m->show_status = true;
+                                manager_set_show_status(m, true);
                                 break;
 
                         case 21:
                                 log_debug("Disabling showing of status.");
-                                m->show_status = false;
+                                manager_set_show_status(m, false);
+                                break;
+
+                        case 22:
+                                log_set_max_level(LOG_DEBUG);
+                                log_notice("Setting log level to debug.");
+                                break;
+
+                        case 23:
+                                log_set_max_level(LOG_INFO);
+                                log_notice("Setting log level to info.");
+                                break;
+
+                        case 27:
+                                log_set_target(LOG_TARGET_CONSOLE);
+                                log_notice("Setting log target to console.");
+                                break;
+
+                        case 28:
+                                log_set_target(LOG_TARGET_KMSG);
+                                log_notice("Setting log target to kmsg.");
+                                break;
+
+                        case 29:
+                                log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+                                log_notice("Setting log target to syslog-or-kmsg.");
                                 break;
 
                         default:
-                                log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo)));
+                                log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
                         }
                 }
                 }
@@ -2236,7 +2311,7 @@ static int process_event(Manager *m, struct epoll_event *ev) {
         assert(m);
         assert(ev);
 
-        assert(w = ev->data.ptr);
+        assert_se(w = ev->data.ptr);
 
         if (w->type == WATCH_INVALID)
                 return 0;
@@ -2326,7 +2401,7 @@ static int process_event(Manager *m, struct epoll_event *ev) {
 int manager_loop(Manager *m) {
         int r;
 
-        RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
+        RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
 
         assert(m);
         m->exit_code = MANAGER_RUNNING;
@@ -2448,7 +2523,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
 
         /* Don't generate audit events if the service was already
          * started and we're just deserializing */
-        if (m->n_deserializing > 0)
+        if (m->n_reloading > 0)
                 return;
 
         if (m->running_as != MANAGER_SYSTEM)
@@ -2489,7 +2564,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
 
         /* Don't generate plymouth events if the service was already
          * started and we're just deserializing */
-        if (m->n_deserializing > 0)
+        if (m->n_reloading > 0)
                 return;
 
         if (m->running_as != MANAGER_SYSTEM)
@@ -2613,7 +2688,7 @@ int manager_open_serialization(Manager *m, FILE **_f) {
         log_debug("Serializing state to %s", path);
         free(path);
 
-        if (!(f = fdopen(fd, "w+")) < 0)
+        if (!(f = fdopen(fd, "w+")))
                 return -errno;
 
         *_f = f;
@@ -2631,6 +2706,11 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
         assert(f);
         assert(fds);
 
+        m->n_reloading ++;
+
+        fprintf(f, "current-job-id=%i\n", m->current_job_id);
+        fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
+
         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);
@@ -2648,13 +2728,22 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
                 fputs(u->meta.id, f);
                 fputc('\n', f);
 
-                if ((r = unit_serialize(u, f, fds)) < 0)
+                if ((r = unit_serialize(u, f, fds)) < 0) {
+                        m->n_reloading --;
                         return r;
+                }
         }
 
+        assert(m->n_reloading > 0);
+        m->n_reloading --;
+
         if (ferror(f))
                 return -EIO;
 
+        r = bus_fdset_add_all(m, fds);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
@@ -2666,10 +2755,10 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
 
         log_debug("Deserializing state...");
 
-        m->n_deserializing ++;
+        m->n_reloading ++;
 
         for (;;) {
-                char line[1024], *l;
+                char line[LINE_MAX], *l;
 
                 if (!fgets(line, sizeof(line), f)) {
                         if (feof(f))
@@ -2686,7 +2775,21 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                 if (l[0] == 0)
                         break;
 
-                if (startswith(l, "initrd-timestamp="))
+                if (startswith(l, "current-job-id=")) {
+                        uint32_t id;
+
+                        if (safe_atou32(l+15, &id) < 0)
+                                log_debug("Failed to parse current job id value %s", l+15);
+                        else
+                                m->current_job_id = MAX(m->current_job_id, id);
+                } else if (startswith(l, "taint-usr=")) {
+                        int b;
+
+                        if ((b = parse_boolean(l+10)) < 0)
+                                log_debug("Failed to parse taint /usr flag %s", l+10);
+                        else
+                                m->taint_usr = m->taint_usr || 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);
@@ -2725,8 +2828,8 @@ finish:
                 goto finish;
         }
 
-        assert(m->n_deserializing > 0);
-        m->n_deserializing --;
+        assert(m->n_reloading > 0);
+        m->n_reloading --;
 
         return r;
 }
@@ -2741,15 +2844,21 @@ int manager_reload(Manager *m) {
         if ((r = manager_open_serialization(m, &f)) < 0)
                 return r;
 
+        m->n_reloading ++;
+
         if (!(fds = fdset_new())) {
+                m->n_reloading --;
                 r = -ENOMEM;
                 goto finish;
         }
 
-        if ((r = manager_serialize(m, f, fds)) < 0)
+        if ((r = manager_serialize(m, f, fds)) < 0) {
+                m->n_reloading --;
                 goto finish;
+        }
 
         if (fseeko(f, 0, SEEK_SET) < 0) {
+                m->n_reloading --;
                 r = -errno;
                 goto finish;
         }
@@ -2760,15 +2869,13 @@ int manager_reload(Manager *m) {
 
         /* Find new unit paths */
         lookup_paths_free(&m->lookup_paths);
-        if ((q = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0)
+        if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
                 r = q;
 
         manager_run_generators(m);
 
         manager_build_unit_path_cache(m);
 
-        m->n_deserializing ++;
-
         /* First, enumerate what we can from all config files */
         if ((q = manager_enumerate(m)) < 0)
                 r = q;
@@ -2784,8 +2891,8 @@ int manager_reload(Manager *m) {
         if ((q = manager_coldplug(m)) < 0)
                 r = q;
 
-        assert(m->n_deserializing > 0);
-        m->n_deserializing ++;
+        assert(m->n_reloading > 0);
+        m->n_reloading--;
 
 finish:
         if (f)
@@ -2807,7 +2914,8 @@ bool manager_is_booting_or_shutting_down(Manager *m) {
                 return true;
 
         /* Is there a job for the shutdown target? */
-        if (((u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET))))
+        u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
+        if (u)
                 return !!u->meta.job;
 
         return false;
@@ -2838,6 +2946,7 @@ bool manager_unit_pending_inactive(Manager *m, const char *name) {
 
 void manager_check_finished(Manager *m) {
         char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
+        usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0;
 
         assert(m);
 
@@ -2851,35 +2960,48 @@ void manager_check_finished(Manager *m) {
 
         if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
 
+                userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
+                total_usec = m->finish_timestamp.monotonic;
+
                 if (dual_timestamp_is_set(&m->initrd_timestamp)) {
+
+                        kernel_usec = m->initrd_timestamp.monotonic;
+                        initrd_usec = m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic;
+
                         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
+                                 format_timespan(kernel, sizeof(kernel), kernel_usec),
+                                 format_timespan(initrd, sizeof(initrd), initrd_usec),
+                                 format_timespan(userspace, sizeof(userspace), userspace_usec),
+                                 format_timespan(sum, sizeof(sum), total_usec));
+                } else {
+                        kernel_usec = m->startup_timestamp.monotonic;
+                        initrd_usec = 0;
+
                         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
+                                 format_timespan(kernel, sizeof(kernel), kernel_usec),
+                                 format_timespan(userspace, sizeof(userspace), userspace_usec),
+                                 format_timespan(sum, sizeof(sum), total_usec));
+                }
+        } else {
+                userspace_usec = initrd_usec = kernel_usec = 0;
+                total_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic;
+
                 log_debug("Startup finished in %s.",
-                          format_timespan(userspace, sizeof(userspace),
-                                          m->finish_timestamp.monotonic - m->startup_timestamp.monotonic));
+                          format_timespan(sum, sizeof(sum), total_usec));
+        }
+
+        bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec);
 
+        sd_notifyf(false,
+                   "READY=1\nSTATUS=Startup finished in %s.",
+                   format_timespan(sum, sizeof(sum), total_usec));
 }
 
 void manager_run_generators(Manager *m) {
         DIR *d = NULL;
         const char *generator_path;
         const char *argv[3];
+        mode_t u;
 
         assert(m);
 
@@ -2894,13 +3016,22 @@ void manager_run_generators(Manager *m) {
         }
 
         if (!m->generator_unit_path) {
-                char *p;
-                char system_path[] = "/run/systemd/generator-XXXXXX",
-                        user_path[] = "/tmp/systemd-generator-XXXXXX";
+                const char *p;
+                char user_path[] = "/tmp/systemd-generator-XXXXXX";
 
-                if (!(p = mkdtemp(m->running_as == MANAGER_SYSTEM ? system_path : user_path))) {
-                        log_error("Failed to generate generator directory: %m");
-                        goto finish;
+                if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
+                        p = "/run/systemd/generator";
+
+                        if (mkdir_p(p, 0755) < 0) {
+                                log_error("Failed to create generator directory: %m");
+                                goto finish;
+                        }
+
+                } else {
+                        if (!(p = mkdtemp(user_path))) {
+                                log_error("Failed to create generator directory: %m");
+                                goto finish;
+                        }
                 }
 
                 if (!(m->generator_unit_path = strdup(p))) {
@@ -2913,7 +3044,9 @@ void manager_run_generators(Manager *m) {
         argv[1] = m->generator_unit_path;
         argv[2] = NULL;
 
+        u = umask(0022);
         execute_directory(generator_path, d, (char**) argv);
+        umask(u);
 
         if (rmdir(m->generator_unit_path) >= 0) {
                 /* Uh? we were able to remove this dir? I guess that
@@ -2951,7 +3084,7 @@ void manager_undo_generators(Manager *m) {
                 return;
 
         strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
-        rm_rf(m->generator_unit_path, false, true);
+        rm_rf(m->generator_unit_path, false, true, false);
 
         free(m->generator_unit_path);
         m->generator_unit_path = NULL;
@@ -3012,6 +3145,35 @@ void manager_recheck_syslog(Manager *m) {
         log_open();
 }
 
+void manager_set_show_status(Manager *m, bool b) {
+        assert(m);
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
+        m->show_status = b;
+
+        if (b)
+                touch("/run/systemd/show-status");
+        else
+                unlink("/run/systemd/show-status");
+}
+
+bool manager_get_show_status(Manager *m) {
+        assert(m);
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return false;
+
+        if (m->show_status)
+                return true;
+
+        /* If Plymouth is running make sure we show the status, so
+         * that there's something nice to see when people press Esc */
+
+        return plymouth_running();
+}
+
 static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
         [MANAGER_SYSTEM] = "system",
         [MANAGER_USER] = "user"