chiark / gitweb /
fsck: show progress while fscking at boot
[elogind.git] / src / manager.c
index ff1c70b4845762446c80382b1051a528aa0e7962..6311c103618a72ec0ab8335ae9ae2aaec5165334 100644 (file)
@@ -58,6 +58,7 @@
 #include "special.h"
 #include "bus-errors.h"
 #include "exit-status.h"
+#include "sd-daemon.h"
 
 /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
 #define GC_QUEUE_ENTRIES_MAX 16
@@ -66,7 +67,8 @@
 #define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
 
 /* Where clients shall send notification messages to */
-#define NOTIFY_SOCKET "/org/freedesktop/systemd1/notify"
+#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify"
+#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify"
 
 static int manager_setup_notify(Manager *m) {
         union {
@@ -74,7 +76,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);
 
@@ -88,11 +91,20 @@ static int manager_setup_notify(Manager *m) {
         sa.sa.sa_family = AF_UNIX;
 
         if (getpid() != 1)
-                snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, NOTIFY_SOCKET "/%llu", random_ull());
-        else
-                strncpy(sa.un.sun_path+1, NOTIFY_SOCKET, sizeof(sa.un.sun_path)-1);
+                snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull());
+        else {
+                unlink(NOTIFY_SOCKET_SYSTEM);
+                strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path));
+        }
+
+        if (sa.un.sun_path[0] == '@')
+                sa.un.sun_path[0] = 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 (bind(m->notify_watch.fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+        if (r < 0) {
                 log_error("bind() failed: %m");
                 return -errno;
         }
@@ -109,7 +121,10 @@ static int manager_setup_notify(Manager *m) {
         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
                 return -errno;
 
-        if (!(m->notify_socket = strdup(sa.un.sun_path+1)))
+        if (sa.un.sun_path[0] == 0)
+                sa.un.sun_path[0] = '@';
+
+        if (!(m->notify_socket = strdup(sa.un.sun_path)))
                 return -ENOMEM;
 
         log_debug("Using notification socket %s", m->notify_socket);
@@ -118,7 +133,7 @@ static int manager_setup_notify(Manager *m) {
 }
 
 static int enable_special_signals(Manager *m) {
-        char fd;
+        int fd;
 
         assert(m);
 
@@ -126,7 +141,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 */
@@ -164,11 +179,23 @@ 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 */
+                        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);
 
@@ -211,12 +238,15 @@ 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)))
                 goto fail;
 
+        if (!(m->default_controllers = strv_new("cpu", NULL)))
+                goto fail;
+
         if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
                 goto fail;
 
@@ -238,7 +268,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)
@@ -251,7 +281,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
                 goto fail;
 
         /* Try to connect to the busses, if possible. */
-        if ((r = bus_init(m)) < 0)
+        if ((r = bus_init(m, running_as != MANAGER_SYSTEM)) < 0)
                 goto fail;
 
 #ifdef HAVE_AUDIT
@@ -259,6 +289,8 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
                 log_error("Failed to connect to audit log: %m");
 #endif
 
+        m->taint_usr = dir_is_empty("/usr") > 0;
+
         *_m = m;
         return 0;
 
@@ -284,7 +316,7 @@ static unsigned manager_dispatch_cleanup_queue(Manager *m) {
 }
 
 enum {
-        GC_OFFSET_IN_PATH,  /* This one is on the path we were travelling */
+        GC_OFFSET_IN_PATH,  /* This one is on the path we were traveling */
         GC_OFFSET_UNSURE,   /* No clue */
         GC_OFFSET_GOOD,     /* We still need this unit */
         GC_OFFSET_BAD,      /* We don't need this unit anymore */
@@ -428,6 +460,8 @@ void manager_free(Manager *m) {
          * around */
         manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
 
+        manager_undo_generators(m);
+
         bus_done(m);
 
         hashmap_free(m->units);
@@ -449,11 +483,12 @@ void manager_free(Manager *m) {
 #endif
 
         free(m->notify_socket);
-        free(m->console);
 
         lookup_paths_free(&m->lookup_paths);
         strv_free(m->environment);
 
+        strv_free(m->default_controllers);
+
         hashmap_free(m->cgroup_bondings);
         set_free_free(m->unit_path_cache);
 
@@ -530,7 +565,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;
                         }
@@ -562,13 +598,15 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
 
         assert(m);
 
+        manager_run_generators(m);
+
         manager_build_unit_path_cache(m);
 
         /* If we will deserialize make sure that during enumeration
          * 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);
@@ -583,8 +621,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;
@@ -753,7 +791,7 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) {
 
         /* Tries to delete one item in the linked list
          * j->transaction_next->transaction_next->... that conflicts
-         * whith another one, in an attempt to make an inconsistent
+         * with another one, in an attempt to make an inconsistent
          * transaction work. */
 
         /* We rely here on the fact that if a merged with b does not
@@ -870,6 +908,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);
         }
@@ -898,7 +939,8 @@ static void transaction_drop_redundant(Manager *m) {
                         LIST_FOREACH(transaction, k, j) {
 
                                 if (!job_is_anchor(k) &&
-                                    job_type_is_redundant(k->type, unit_active_state(k->unit)))
+                                    (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) &&
+                                    (!k->unit->meta.job || !job_type_is_conflicting(k->type, k->unit->meta.job->type)))
                                         continue;
 
                                 changes_something = true;
@@ -908,7 +950,7 @@ static void transaction_drop_redundant(Manager *m) {
                         if (changes_something)
                                 continue;
 
-                        log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
+                        /* log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type)); */
                         transaction_delete_job(m, j, false);
                         again = true;
                         break;
@@ -982,7 +1024,7 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned
 
 
                 if (delete) {
-                        log_warning("Breaking ordering cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type));
+                        log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->meta.id, job_type_to_string(delete->type));
                         transaction_delete_unit(m, delete->unit);
                         return -EAGAIN;
                 }
@@ -1060,10 +1102,15 @@ static void transaction_collect_garbage(Manager *m) {
                 again = false;
 
                 HASHMAP_FOREACH(j, m->transaction_jobs, i) {
-                        if (j->object_list)
+                        if (j->object_list) {
+                                /* log_debug("Keeping job %s/%s because of %s/%s", */
+                                /*           j->unit->meta.id, job_type_to_string(j->type), */
+                                /*           j->object_list->subject ? j->object_list->subject->unit->meta.id : "root", */
+                                /*           j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
                                 continue;
+                        }
 
-                        log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
+                        /* log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type)); */
                         transaction_delete_job(m, j, true);
                         again = true;
                         break;
@@ -1128,19 +1175,20 @@ 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;
 
                                 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;
@@ -1154,13 +1202,27 @@ 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 */
+                HASHMAP_FOREACH(j, m->jobs, i) {
+                        assert(j->installed);
+
+                        if (hashmap_get(m->transaction_jobs, j->unit))
+                                continue;
+
+                        job_finish_and_invalidate(j, JOB_CANCELED);
+                }
+        }
+
         HASHMAP_FOREACH(j, m->transaction_jobs, i) {
                 /* Assume merged */
                 assert(!j->transaction_prev);
@@ -1174,14 +1236,17 @@ static int transaction_apply(Manager *m) {
         }
 
         while ((j = hashmap_steal_first(m->transaction_jobs))) {
-                if (j->installed)
+                if (j->installed) {
+                        /* log_debug("Skipping already installed job %s/%s as %u", j->unit->meta.id, job_type_to_string(j->type), (unsigned) j->id); */
                         continue;
+                }
 
                 if (j->unit->meta.job)
                         job_free(j->unit->meta.job);
 
                 j->unit->meta.job = j;
                 j->installed = true;
+                m->n_installed_jobs ++;
 
                 /* We're fully installed. Now let's free data we don't
                  * need anymore. */
@@ -1192,6 +1257,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. */
@@ -1226,7 +1293,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 */
@@ -1235,7 +1302,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 */
@@ -1259,13 +1327,14 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
                         break;
 
                 if (r != -EAGAIN) {
-                        log_warning("Requested transaction contains unmergable jobs: %s", bus_error(e, r));
+                        log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
                         goto rollback;
                 }
 
                 /* 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 ... */
@@ -1282,7 +1351,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;
         }
@@ -1303,7 +1372,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o
         assert(m);
         assert(unit);
 
-        /* Looks for an axisting prospective job and returns that. If
+        /* Looks for an existing prospective job and returns that. If
          * it doesn't exist it is created and added to the prospective
          * jobs list. */
 
@@ -1339,7 +1408,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o
         if (is_new)
                 *is_new = true;
 
-        log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type));
+        /* log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type)); */
 
         return j;
 }
@@ -1385,6 +1454,8 @@ static int transaction_add_job_and_dependencies(
                 bool matters,
                 bool override,
                 bool conflicts,
+                bool ignore_requirements,
+                bool ignore_order,
                 DBusError *e,
                 Job **_ret) {
         Job *ret;
@@ -1397,15 +1468,30 @@ static int transaction_add_job_and_dependencies(
         assert(type < _JOB_TYPE_MAX);
         assert(unit);
 
-        if (unit->meta.load_state != UNIT_LOADED && unit->meta.load_state != UNIT_ERROR) {
+        /* log_debug("Pulling in %s/%s from %s/%s", */
+        /*           unit->meta.id, job_type_to_string(type), */
+        /*           by ? by->unit->meta.id : "NA", */
+        /*           by ? job_type_to_string(by->type) : "NA"); */
+
+        if (unit->meta.load_state != UNIT_LOADED &&
+            unit->meta.load_state != UNIT_ERROR &&
+            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;
         }
 
         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.",
+                dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
+                               "Unit %s failed to load: %s. "
+                               "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;
+        }
+
+        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;
         }
 
@@ -1418,19 +1504,52 @@ static int transaction_add_job_and_dependencies(
         if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
                 return -ENOMEM;
 
+        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) {
+        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, 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)
+                                                dbus_error_free(e);
+                                }
+
+                        set_free(following);
+                }
+
                 /* 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, e, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
+                                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;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        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, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
 
                         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) {
+                                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)
@@ -1438,7 +1557,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, 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)
@@ -1446,11 +1565,17 @@ 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, e, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
+                                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;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
 
                         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, e, NULL)) < 0 && r != -EBADR) {
+                                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)
@@ -1458,18 +1583,44 @@ 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, e, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
+                                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;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
 
                         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)
-                                        goto fail;
+                                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)
+                                                dbus_error_free(e);
+                                }
 
                 } 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, e, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
+                                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;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
+
+                        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, ignore_order, e, NULL)) < 0) {
+
+                                        if (r != -EBADR)
+                                                goto fail;
+
+                                        if (e)
+                                                dbus_error_free(e);
+                                }
                 }
 
                 /* JOB_VERIFY_STARTED, JOB_RELOAD require no dependency handling */
@@ -1498,18 +1649,18 @@ 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 */
-                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? */
                 if (hashmap_get(m->transaction_jobs, u))
                         continue;
 
-                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, 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));
         }
 
@@ -1535,9 +1686,11 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
                 return -EPERM;
         }
 
-        log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type));
+        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, 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;
         }
@@ -1631,7 +1784,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;
         }
@@ -1716,7 +1869,7 @@ void manager_clear_jobs(Manager *m) {
         transaction_abort(m);
 
         while ((j = hashmap_first(m->jobs)))
-                job_free(j);
+                job_finish_and_invalidate(j, JOB_CANCELED);
 }
 
 unsigned manager_dispatch_run_queue(Manager *m) {
@@ -1923,7 +2076,7 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
 
         dbus_error_init(&error);
 
-        log_info("Activating special unit %s", name);
+        log_debug("Activating special unit %s", name);
 
         if ((r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL)) < 0)
                 log_error("Failed to enqueue %s job: %s", name, bus_error(&error, r));
@@ -1952,7 +2105,17 @@ static int manager_process_signal_fd(Manager *m) {
                         return -errno;
                 }
 
-                log_debug("Received SIG%s", strna(signal_to_string(sfsi.ssi_signo)));
+                if (sfsi.ssi_pid > 0) {
+                        char *p = NULL;
+
+                        get_process_name(sfsi.ssi_pid, &p);
+
+                        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);
+                } else
+                        log_debug("Received SIG%s.", strna(signal_to_string(sfsi.ssi_signo)));
 
                 switch (sfsi.ssi_signo) {
 
@@ -1977,7 +2140,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;
                         }
@@ -2005,7 +2168,7 @@ static int manager_process_signal_fd(Manager *m) {
 
                         if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
                                 log_info("Trying to reconnect to bus...");
-                                bus_init(m);
+                                bus_init(m, true);
                         }
 
                         if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
@@ -2048,23 +2211,79 @@ 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;
                         }
 
-                        log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo)));
+                        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;
+                        }
+
+                        switch (sfsi.ssi_signo - SIGRTMIN) {
+
+                        case 20:
+                                log_debug("Enabling showing of status.");
+                                manager_set_show_status(m, true);
+                                break;
+
+                        case 21:
+                                log_debug("Disabling showing of status.");
+                                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)));
+                        }
                 }
                 }
         }
@@ -2082,7 +2301,10 @@ 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;
 
         switch (w->type) {
 
@@ -2140,6 +2362,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);
@@ -2154,6 +2381,7 @@ static int process_event(Manager *m, struct epoll_event *ev) {
                 break;
 
         default:
+                log_error("event type=%i", w->type);
                 assert_not_reached("Unknown epoll event type.");
         }
 
@@ -2163,7 +2391,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;
@@ -2172,6 +2400,8 @@ int manager_loop(Manager *m) {
         set_free_free(m->unit_path_cache);
         m->unit_path_cache = NULL;
 
+        manager_check_finished(m);
+
         /* There might still be some zombies hanging around from
          * before we were exec()'ed. Leat's reap them */
         if ((r = manager_dispatch_sigchld(m)) < 0)
@@ -2205,6 +2435,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)
@@ -2280,7 +2513,13 @@ 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)
+                return;
+
+        if (u->meta.type != UNIT_SERVICE)
                 return;
 
         if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) {
@@ -2288,14 +2527,93 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
                 return;
         }
 
-        if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0)
-                log_error("Failed to send audit message: %m");
+        if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
+                log_warning("Failed to send audit message: %m");
+
+                if (errno == EPERM) {
+                        /* We aren't allowed to send audit messages?
+                         * Then let's not retry again, to avoid
+                         * spamming the user with the same and same
+                         * messages over and over. */
+
+                        audit_close(m->audit_fd);
+                        m->audit_fd = -1;
+                }
+        }
 
         free(p);
 #endif
 
 }
 
+void manager_send_unit_plymouth(Manager *m, Unit *u) {
+        int fd = -1;
+        union sockaddr_union sa;
+        int n = 0;
+        char *message = NULL;
+
+        /* Don't generate plymouth events if the service was already
+         * started and we're just deserializing */
+        if (m->n_reloading > 0)
+                return;
+
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
+
+        if (u->meta.type != UNIT_SERVICE &&
+            u->meta.type != UNIT_MOUNT &&
+            u->meta.type != UNIT_SWAP)
+                return;
+
+        /* We set SOCK_NONBLOCK here so that we rather drop the
+         * message then wait for plymouth */
+        if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
+                log_error("socket() failed: %m");
+                return;
+        }
+
+        zero(sa);
+        sa.sa.sa_family = AF_UNIX;
+        strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
+        if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+
+                if (errno != EPIPE &&
+                    errno != EAGAIN &&
+                    errno != ENOENT &&
+                    errno != ECONNREFUSED &&
+                    errno != ECONNRESET &&
+                    errno != ECONNABORTED)
+                        log_error("connect() failed: %m");
+
+                goto finish;
+        }
+
+        if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->meta.id) + 1), u->meta.id, &n) < 0) {
+                log_error("Out of memory");
+                goto finish;
+        }
+
+        errno = 0;
+        if (write(fd, message, n + 1) != n + 1) {
+
+                if (errno != EPIPE &&
+                    errno != EAGAIN &&
+                    errno != ENOENT &&
+                    errno != ECONNREFUSED &&
+                    errno != ECONNRESET &&
+                    errno != ECONNABORTED)
+                        log_error("Failed to write Plymouth message: %m");
+
+                goto finish;
+        }
+
+finish:
+        if (fd >= 0)
+                close_nointr_nofail(fd);
+
+        free(message);
+}
+
 void manager_dispatch_bus_name_owner_changed(
                 Manager *m,
                 const char *name,
@@ -2331,22 +2649,20 @@ void manager_dispatch_bus_query_pid_done(
 }
 
 int manager_open_serialization(Manager *m, FILE **_f) {
-        char *path;
+        char *path = NULL;
         mode_t saved_umask;
         int fd;
         FILE *f;
 
         assert(_f);
 
-        if (m->running_as == MANAGER_SYSTEM) {
-                mkdir_p("/dev/.systemd", 0755);
+        if (m->running_as == MANAGER_SYSTEM)
+                asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
+        else
+                asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
 
-                if (asprintf(&path, "/dev/.systemd/dump-%lu-XXXXXX", (unsigned long) getpid()) < 0)
-                        return -ENOMEM;
-        } else {
-                if (asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid()) < 0)
-                        return -ENOMEM;
-        }
+        if (!path)
+                return -ENOMEM;
 
         saved_umask = umask(0077);
         fd = mkostemp(path, O_RDWR|O_CLOEXEC);
@@ -2362,7 +2678,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;
@@ -2380,9 +2696,16 @@ 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);
+        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);
+
+        fputc('\n', f);
 
         HASHMAP_FOREACH_KEY(u, t, m->units, i) {
                 if (u->meta.id != t)
@@ -2395,13 +2718,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;
 }
 
@@ -2413,10 +2745,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))
@@ -2433,16 +2765,27 @@ 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 (startswith(l, "current-job-id=")) {
+                        uint32_t id;
 
-                        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 (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);
+                else if (startswith(l, "finish-timestamp="))
+                        dual_timestamp_deserialize(l+17, &m->finish_timestamp);
+                else
                         log_debug("Unknown serialization item '%s'", l);
         }
 
@@ -2475,8 +2818,8 @@ finish:
                 goto finish;
         }
 
-        assert(m->n_deserializing > 0);
-        m->n_deserializing --;
+        assert(m->n_reloading > 0);
+        m->n_reloading --;
 
         return r;
 }
@@ -2491,28 +2834,37 @@ 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;
         }
 
         /* From here on there is no way back. */
         manager_clear_jobs_and_units(m);
+        manager_undo_generators(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;
 
-        m->n_deserializing ++;
+        manager_run_generators(m);
+
+        manager_build_unit_path_cache(m);
 
         /* First, enumerate what we can from all config files */
         if ((q = manager_enumerate(m)) < 0)
@@ -2529,8 +2881,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)
@@ -2552,7 +2904,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;
@@ -2568,45 +2921,252 @@ void manager_reset_failed(Manager *m) {
                 unit_reset_failed(u);
 }
 
-int manager_set_console(Manager *m, const char *console) {
-        char *c;
+bool manager_unit_pending_inactive(Manager *m, const char *name) {
+        Unit *u;
+
+        assert(m);
+        assert(name);
+
+        /* Returns true if the unit is inactive or going down */
+        if (!(u = manager_get_unit(m, name)))
+                return true;
+
+        return unit_pending_inactive(u);
+}
+
+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);
 
-        if (!(c = strdup(console)))
-                return -ENOMEM;
+        if (dual_timestamp_is_set(&m->finish_timestamp))
+                return;
+
+        if (hashmap_size(m->jobs) > 0)
+                return;
+
+        dual_timestamp_get(&m->finish_timestamp);
+
+        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), 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), 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(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);
+
+        generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
+        if (!(d = opendir(generator_path))) {
+
+                if (errno == ENOENT)
+                        return;
+
+                log_error("Failed to enumerate generator directory: %m");
+                return;
+        }
+
+        if (!m->generator_unit_path) {
+                const char *p;
+                char user_path[] = "/tmp/systemd-generator-XXXXXX";
+
+                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))) {
+                        log_error("Failed to allocate generator unit path.");
+                        goto finish;
+                }
+        }
+
+        argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
+        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
+                 * means the directory was empty, hence let's shortcut
+                 * this */
+
+                free(m->generator_unit_path);
+                m->generator_unit_path = NULL;
+                goto finish;
+        }
+
+        if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) {
+                char **l;
+
+                if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) {
+                        log_error("Failed to add generator directory to unit search path: %m");
+                        goto finish;
+                }
+
+                strv_free(m->lookup_paths.unit_path);
+                m->lookup_paths.unit_path = l;
+
+                log_debug("Added generator unit path %s to search path.", m->generator_unit_path);
+        }
+
+finish:
+        if (d)
+                closedir(d);
+}
+
+void manager_undo_generators(Manager *m) {
+        assert(m);
+
+        if (!m->generator_unit_path)
+                return;
+
+        strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
+        rm_rf(m->generator_unit_path, false, true, false);
 
-        free(m->console);
-        m->console = c;
+        free(m->generator_unit_path);
+        m->generator_unit_path = NULL;
+}
+
+int manager_set_default_controllers(Manager *m, char **controllers) {
+        char **l;
 
-        log_debug("Using kernel console %s", c);
+        assert(m);
+
+        if (!(l = strv_copy(controllers)))
+                return -ENOMEM;
+
+        strv_free(m->default_controllers);
+        m->default_controllers = l;
 
         return 0;
 }
 
-bool manager_unit_pending_inactive(Manager *m, const char *name) {
+void manager_recheck_syslog(Manager *m) {
         Unit *u;
 
         assert(m);
-        assert(name);
 
-        /* Returns true if the unit is inactive or going down */
+        if (m->running_as != MANAGER_SYSTEM)
+                return;
 
-        if (!(u = manager_get_unit(m, name)))
-                return true;
+        if ((u = manager_get_unit(m, SPECIAL_SYSLOG_SOCKET))) {
+                SocketState state;
 
-        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)))
-                return true;
+                state = SOCKET(u)->state;
+
+                if (state != SOCKET_DEAD &&
+                    state != SOCKET_FAILED &&
+                    state != SOCKET_RUNNING) {
+
+                        /* Hmm, the socket is not set up, or is still
+                         * listening, let's better not try to use
+                         * it. Note that we have no problem if the
+                         * socket is completely down, since there
+                         * might be a foreign /dev/log socket around
+                         * and we want to make use of that.
+                         */
+
+                        log_close_syslog();
+                        return;
+                }
+        }
 
-        if (u->meta.job && u->meta.job->type == JOB_STOP)
+        if ((u = manager_get_unit(m, SPECIAL_SYSLOG_TARGET)))
+                if (TARGET(u)->state != TARGET_ACTIVE) {
+                        log_close_syslog();
+                        return;
+                }
+
+        /* Hmm, OK, so the socket is either fully up, or fully down,
+         * and the target is up, then let's make use of the socket */
+        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;
 
-        return false;
+        /* 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_SESSION] = "session"
+        [MANAGER_USER] = "user"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(manager_running_as, ManagerRunningAs);