[systemd-commits] 13 commits - Makefile.am configure.ac man/sd_pid_get_session.xml src/cryptsetup src/cryptsetup-generator.c src/cryptsetup.c src/generate-kbd-model-map src/journal src/kbd-model-map src/locale src/localed.c src/login src/logs-show.c src/logs-show.h src/nspawn.c src/readahead src/sd-id128.c src/socket.c src/systemctl.c

Lennart Poettering lennart at kemper.freedesktop.org
Tue Jan 3 12:09:06 PST 2012


 Makefile.am                           |  203 +++++++------
 configure.ac                          |   16 +
 man/sd_pid_get_session.xml            |   40 +-
 src/cryptsetup-generator.c            |  298 -------------------
 src/cryptsetup.c                      |  529 ----------------------------------
 src/cryptsetup/cryptsetup-generator.c |  298 +++++++++++++++++++
 src/cryptsetup/cryptsetup.c           |  529 ++++++++++++++++++++++++++++++++++
 src/generate-kbd-model-map            |   33 --
 src/journal/journal-send.c            |   16 -
 src/journal/journalctl.c              |  311 -------------------
 src/journal/journald.c                |   85 +++--
 src/journal/sd-journal.c              |  161 ++++++----
 src/journal/sd-journal.h              |    2 
 src/kbd-model-map                     |   72 ----
 src/locale/generate-kbd-model-map     |   33 ++
 src/locale/kbd-model-map              |   72 ++++
 src/login/libsystemd-login.sym        |    5 
 src/login/sd-login.c                  |   27 +
 src/login/sd-login.h                  |    4 
 src/logs-show.c                       |  404 +++++++++++++++++++++++++
 src/logs-show.h                       |   49 +++
 src/nspawn.c                          |   12 
 src/readahead/sd-readahead.c          |   14 
 src/readahead/sd-readahead.h          |   10 
 src/sd-id128.c                        |   30 +
 src/socket.c                          |   16 -
 src/systemctl.c                       |    4 
 27 files changed, 1814 insertions(+), 1459 deletions(-)

New commits:
commit 86aa7ba4f9969bbfc75ebd51f944313695f1a0a1
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 21:08:28 2012 +0100

    systemctl: hook up systemctl with the journal

diff --git a/Makefile.am b/Makefile.am
index 8bb5b9d..6c0fd05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -98,7 +98,8 @@ AM_CPPFLAGS = \
 	-DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
 	-I $(top_srcdir)/src \
 	-I $(top_srcdir)/src/readahead \
-	-I $(top_srcdir)/src/login
+	-I $(top_srcdir)/src/login \
+	-I $(top_srcdir)/src/journal
 
 if TARGET_GENTOO
 AM_CPPFLAGS += \
@@ -923,7 +924,8 @@ systemctl_SOURCES = \
 	src/unit-name.c \
 	src/pager.c \
 	src/install.c \
-	src/spawn-agent.c
+	src/spawn-agent.c \
+        src/logs-show.c
 
 systemctl_CFLAGS = \
 	$(AM_CFLAGS) \
@@ -932,6 +934,7 @@ systemctl_CFLAGS = \
 systemctl_LDADD = \
 	libsystemd-basic.la \
 	libsystemd-daemon.la \
+	libsystemd-journal.la \
 	$(DBUS_LIBS)
 
 systemd_notify_SOURCES = \
@@ -1189,14 +1192,12 @@ endif
 
 systemd_journalctl_SOURCES = \
 	src/journal/journalctl.c \
-	src/journal/sd-journal.c \
-	src/journal/journal-file.c \
-	src/journal/lookup3.c \
-	src/sd-id128.c \
-	src/pager.c
+	src/pager.c \
+        src/logs-show.c
 
 systemd_journalctl_LDADD = \
-	libsystemd-basic.la
+	libsystemd-basic.la \
+        libsystemd-journal.la
 
 if HAVE_XZ
 systemd_journalctl_SOURCES += \
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 7015182..4c20ff6 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -35,319 +35,14 @@
 #include "util.h"
 #include "build.h"
 #include "pager.h"
+#include "logs-show.h"
 
-#define PRINT_THRESHOLD 128
-
-static enum {
-        OUTPUT_SHORT,
-        OUTPUT_VERBOSE,
-        OUTPUT_EXPORT,
-        OUTPUT_JSON,
-        _OUTPUT_MAX
-} arg_output = OUTPUT_SHORT;
+static output_mode arg_output = OUTPUT_SHORT;
 
 static bool arg_follow = false;
 static bool arg_show_all = false;
 static bool arg_no_pager = false;
 
-static bool contains_unprintable(const void *p, size_t l) {
-        const char *j;
-
-        for (j = p; j < (const char *) p + l; j++)
-                if (*j < ' ' || *j >= 127)
-                        return true;
-
-        return false;
-}
-
-static int output_short(sd_journal *j, unsigned line) {
-        int r;
-        uint64_t realtime;
-        time_t t;
-        struct tm tm;
-        char buf[64];
-        const void *data;
-        size_t length;
-        size_t n = 0;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime: %s", strerror(-r));
-                return r;
-        }
-
-        t = (time_t) (realtime / USEC_PER_SEC);
-        if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
-                log_error("Failed to format time.");
-                return -EINVAL;
-        }
-
-        fputs(buf, stdout);
-        n += strlen(buf);
-
-        if (sd_journal_get_data(j, "_HOSTNAME", &data, &length) >= 0 &&
-            (arg_show_all || (!contains_unprintable(data, length) &&
-                              length < PRINT_THRESHOLD))) {
-                printf(" %.*s", (int) length - 10, ((const char*) data) + 10);
-                n += length - 10 + 1;
-        }
-
-        if (sd_journal_get_data(j, "MESSAGE", &data, &length) >= 0) {
-                if (arg_show_all)
-                        printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
-                else if (contains_unprintable(data, length))
-                        fputs(" [blob data]", stdout);
-                else if (length - 8 + n < columns())
-                        printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
-                else if (n < columns()) {
-                        char *e;
-
-                        e = ellipsize_mem((const char *) data + 8, length - 8, columns() - n - 2, 90);
-
-                        if (!e)
-                                printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
-                        else
-                                printf(" %s", e);
-
-                        free(e);
-                }
-        }
-
-        fputc('\n', stdout);
-
-        return 0;
-}
-
-static int output_verbose(sd_journal *j, unsigned line) {
-        const void *data;
-        size_t length;
-        char *cursor;
-        uint64_t realtime;
-        char ts[FORMAT_TIMESTAMP_MAX];
-        int r;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_cursor(j, &cursor);
-        if (r < 0) {
-                log_error("Failed to get cursor: %s", strerror(-r));
-                return r;
-        }
-
-        printf("%s [%s]\n",
-               format_timestamp(ts, sizeof(ts), realtime),
-               cursor);
-
-        free(cursor);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-                if (!arg_show_all && (length > PRINT_THRESHOLD ||
-                                      contains_unprintable(data, length))) {
-                        const char *c;
-
-                        c = memchr(data, '=', length);
-                        if (!c) {
-                                log_error("Invalid field.");
-                                return -EINVAL;
-                        }
-
-                        printf("\t%.*s=[blob data]\n",
-                               (int) (c - (const char*) data),
-                               (const char*) data);
-                } else
-                        printf("\t%.*s\n", (int) length, (const char*) data);
-        }
-
-        return 0;
-}
-
-static int output_export(sd_journal *j, unsigned line) {
-        sd_id128_t boot_id;
-        char sid[33];
-        int r;
-        usec_t realtime, monotonic;
-        char *cursor;
-        const void *data;
-        size_t length;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
-        if (r < 0) {
-                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_cursor(j, &cursor);
-        if (r < 0) {
-                log_error("Failed to get cursor: %s", strerror(-r));
-                return r;
-        }
-
-        printf(".cursor=%s\n"
-               ".realtime=%llu\n"
-               ".monotonic=%llu\n"
-               ".boot_id=%s\n",
-               cursor,
-               (unsigned long long) realtime,
-               (unsigned long long) monotonic,
-               sd_id128_to_string(boot_id, sid));
-
-        free(cursor);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-
-                if (contains_unprintable(data, length)) {
-                        const char *c;
-                        uint64_t le64;
-
-                        c = memchr(data, '=', length);
-                        if (!c) {
-                                log_error("Invalid field.");
-                                return -EINVAL;
-                        }
-
-                        fwrite(data, c - (const char*) data, 1, stdout);
-                        fputc('\n', stdout);
-                        le64 = htole64(length - (c - (const char*) data) - 1);
-                        fwrite(&le64, sizeof(le64), 1, stdout);
-                        fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
-                } else
-                        fwrite(data, length, 1, stdout);
-
-                fputc('\n', stdout);
-        }
-
-        fputc('\n', stdout);
-
-        return 0;
-}
-
-static void json_escape(const char* p, size_t l) {
-
-        if (contains_unprintable(p, l)) {
-                bool not_first = false;
-
-                fputs("[ ", stdout);
-
-                while (l > 0) {
-                        if (not_first)
-                                printf(", %u", (uint8_t) *p);
-                        else {
-                                not_first = true;
-                                printf("%u", (uint8_t) *p);
-                        }
-
-                        p++;
-                        l--;
-                }
-
-                fputs(" ]", stdout);
-        } else {
-                fputc('\"', stdout);
-
-                while (l > 0) {
-                        if (*p == '"' || *p == '\\') {
-                                fputc('\\', stdout);
-                                fputc(*p, stdout);
-                        } else
-                                fputc(*p, stdout);
-
-                        p++;
-                        l--;
-                }
-
-                fputc('\"', stdout);
-        }
-}
-
-static int output_json(sd_journal *j, unsigned line) {
-        uint64_t realtime, monotonic;
-        char *cursor;
-        const void *data;
-        size_t length;
-        sd_id128_t boot_id;
-        char sid[33];
-        int r;
-
-        assert(j);
-
-        r = sd_journal_get_realtime_usec(j, &realtime);
-        if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
-        if (r < 0) {
-                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
-                return r;
-        }
-
-        r = sd_journal_get_cursor(j, &cursor);
-        if (r < 0) {
-                log_error("Failed to get cursor: %s", strerror(-r));
-                return r;
-        }
-
-        if (line == 1)
-                fputc('\n', stdout);
-        else
-                fputs(",\n", stdout);
-
-        printf("{\n"
-               "\t\".cursor\" : \"%s\",\n"
-               "\t\".realtime\" : %llu,\n"
-               "\t\".monotonic\" : %llu,\n"
-               "\t\".boot_id\" : \"%s\"",
-               cursor,
-               (unsigned long long) realtime,
-               (unsigned long long) monotonic,
-               sd_id128_to_string(boot_id, sid));
-
-        free(cursor);
-
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
-                const char *c;
-
-                c = memchr(data, '=', length);
-                if (!c) {
-                        log_error("Invalid field.");
-                        return -EINVAL;
-                }
-
-                fputs(",\n\t", stdout);
-                json_escape(data, c - (const char*) data);
-                fputs(" : ", stdout);
-                json_escape(c + 1, length - (c - (const char*) data) - 1);
-        }
-
-        fputs("\n}", stdout);
-        fflush(stdout);
-
-        return 0;
-}
-
-static int (*output_funcs[_OUTPUT_MAX])(sd_journal*j, unsigned line) = {
-        [OUTPUT_SHORT] = output_short,
-        [OUTPUT_VERBOSE] = output_verbose,
-        [OUTPUT_EXPORT] = output_export,
-        [OUTPUT_JSON] = output_json
-};
 
 static int help(void) {
 
@@ -503,7 +198,7 @@ int main(int argc, char *argv[]) {
 
                         line ++;
 
-                        r = output_funcs[arg_output](j, line);
+                        r = output_journal(j, arg_output, line, arg_show_all);
                         if (r < 0)
                                 goto finish;
                 }
diff --git a/src/logs-show.c b/src/logs-show.c
new file mode 100644
index 0000000..d178f95
--- /dev/null
+++ b/src/logs-show.c
@@ -0,0 +1,404 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <time.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "logs-show.h"
+#include "log.h"
+#include "util.h"
+
+#define PRINT_THRESHOLD 128
+
+static bool contains_unprintable(const void *p, size_t l) {
+        const char *j;
+
+        for (j = p; j < (const char *) p + l; j++)
+                if (*j < ' ' || *j >= 127)
+                        return true;
+
+        return false;
+}
+
+static int output_short(sd_journal *j, unsigned line, bool show_all) {
+        int r;
+        uint64_t realtime;
+        time_t t;
+        struct tm tm;
+        char buf[64];
+        const void *data;
+        size_t length;
+        size_t n = 0;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime: %s", strerror(-r));
+                return r;
+        }
+
+        t = (time_t) (realtime / USEC_PER_SEC);
+        if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
+                log_error("Failed to format time.");
+                return -EINVAL;
+        }
+
+        fputs(buf, stdout);
+        n += strlen(buf);
+
+        if (sd_journal_get_data(j, "_HOSTNAME", &data, &length) >= 0 &&
+            (show_all || (!contains_unprintable(data, length) &&
+                          length < PRINT_THRESHOLD))) {
+                printf(" %.*s", (int) length - 10, ((const char*) data) + 10);
+                n += length - 10 + 1;
+        }
+
+        if (sd_journal_get_data(j, "MESSAGE", &data, &length) >= 0) {
+                if (show_all)
+                        printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
+                else if (contains_unprintable(data, length))
+                        fputs(" [blob data]", stdout);
+                else if (length - 8 + n < columns())
+                        printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
+                else if (n < columns()) {
+                        char *e;
+
+                        e = ellipsize_mem((const char *) data + 8, length - 8, columns() - n - 2, 90);
+
+                        if (!e)
+                                printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
+                        else
+                                printf(" %s", e);
+
+                        free(e);
+                }
+        }
+
+        fputc('\n', stdout);
+
+        return 0;
+}
+
+static int output_verbose(sd_journal *j, unsigned line, bool show_all) {
+        const void *data;
+        size_t length;
+        char *cursor;
+        uint64_t realtime;
+        char ts[FORMAT_TIMESTAMP_MAX];
+        int r;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_cursor(j, &cursor);
+        if (r < 0) {
+                log_error("Failed to get cursor: %s", strerror(-r));
+                return r;
+        }
+
+        printf("%s [%s]\n",
+               format_timestamp(ts, sizeof(ts), realtime),
+               cursor);
+
+        free(cursor);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+                if (!show_all && (length > PRINT_THRESHOLD ||
+                                  contains_unprintable(data, length))) {
+                        const char *c;
+
+                        c = memchr(data, '=', length);
+                        if (!c) {
+                                log_error("Invalid field.");
+                                return -EINVAL;
+                        }
+
+                        printf("\t%.*s=[blob data]\n",
+                               (int) (c - (const char*) data),
+                               (const char*) data);
+                } else
+                        printf("\t%.*s\n", (int) length, (const char*) data);
+        }
+
+        return 0;
+}
+
+static int output_export(sd_journal *j, unsigned line, bool show_all) {
+        sd_id128_t boot_id;
+        char sid[33];
+        int r;
+        usec_t realtime, monotonic;
+        char *cursor;
+        const void *data;
+        size_t length;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
+        if (r < 0) {
+                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_cursor(j, &cursor);
+        if (r < 0) {
+                log_error("Failed to get cursor: %s", strerror(-r));
+                return r;
+        }
+
+        printf(".cursor=%s\n"
+               ".realtime=%llu\n"
+               ".monotonic=%llu\n"
+               ".boot_id=%s\n",
+               cursor,
+               (unsigned long long) realtime,
+               (unsigned long long) monotonic,
+               sd_id128_to_string(boot_id, sid));
+
+        free(cursor);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+
+                if (contains_unprintable(data, length)) {
+                        const char *c;
+                        uint64_t le64;
+
+                        c = memchr(data, '=', length);
+                        if (!c) {
+                                log_error("Invalid field.");
+                                return -EINVAL;
+                        }
+
+                        fwrite(data, c - (const char*) data, 1, stdout);
+                        fputc('\n', stdout);
+                        le64 = htole64(length - (c - (const char*) data) - 1);
+                        fwrite(&le64, sizeof(le64), 1, stdout);
+                        fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
+                } else
+                        fwrite(data, length, 1, stdout);
+
+                fputc('\n', stdout);
+        }
+
+        fputc('\n', stdout);
+
+        return 0;
+}
+
+static void json_escape(const char* p, size_t l) {
+
+        if (contains_unprintable(p, l)) {
+                bool not_first = false;
+
+                fputs("[ ", stdout);
+
+                while (l > 0) {
+                        if (not_first)
+                                printf(", %u", (uint8_t) *p);
+                        else {
+                                not_first = true;
+                                printf("%u", (uint8_t) *p);
+                        }
+
+                        p++;
+                        l--;
+                }
+
+                fputs(" ]", stdout);
+        } else {
+                fputc('\"', stdout);
+
+                while (l > 0) {
+                        if (*p == '"' || *p == '\\') {
+                                fputc('\\', stdout);
+                                fputc(*p, stdout);
+                        } else
+                                fputc(*p, stdout);
+
+                        p++;
+                        l--;
+                }
+
+                fputc('\"', stdout);
+        }
+}
+
+static int output_json(sd_journal *j, unsigned line, bool show_all) {
+        uint64_t realtime, monotonic;
+        char *cursor;
+        const void *data;
+        size_t length;
+        sd_id128_t boot_id;
+        char sid[33];
+        int r;
+
+        assert(j);
+
+        r = sd_journal_get_realtime_usec(j, &realtime);
+        if (r < 0) {
+                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
+        if (r < 0) {
+                log_error("Failed to get monotonic timestamp: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_journal_get_cursor(j, &cursor);
+        if (r < 0) {
+                log_error("Failed to get cursor: %s", strerror(-r));
+                return r;
+        }
+
+        if (line == 1)
+                fputc('\n', stdout);
+        else
+                fputs(",\n", stdout);
+
+        printf("{\n"
+               "\t\".cursor\" : \"%s\",\n"
+               "\t\".realtime\" : %llu,\n"
+               "\t\".monotonic\" : %llu,\n"
+               "\t\".boot_id\" : \"%s\"",
+               cursor,
+               (unsigned long long) realtime,
+               (unsigned long long) monotonic,
+               sd_id128_to_string(boot_id, sid));
+
+        free(cursor);
+
+        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+                const char *c;
+
+                c = memchr(data, '=', length);
+                if (!c) {
+                        log_error("Invalid field.");
+                        return -EINVAL;
+                }
+
+                fputs(",\n\t", stdout);
+                json_escape(data, c - (const char*) data);
+                fputs(" : ", stdout);
+                json_escape(c + 1, length - (c - (const char*) data) - 1);
+        }
+
+        fputs("\n}", stdout);
+        fflush(stdout);
+
+        return 0;
+}
+
+static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, bool show_all) = {
+        [OUTPUT_SHORT] = output_short,
+        [OUTPUT_VERBOSE] = output_verbose,
+        [OUTPUT_EXPORT] = output_export,
+        [OUTPUT_JSON] = output_json
+};
+
+int output_journal(sd_journal *j, output_mode mode, unsigned line, bool show_all) {
+        assert(mode < _OUTPUT_MODE_MAX);
+
+        return output_funcs[mode](j, line, show_all);
+}
+
+int show_journal_by_service(
+                const char *service,
+                output_mode mode,
+                const char *prefix,
+                unsigned n_columns,
+                usec_t not_before,
+                unsigned how_many,
+                bool show_all) {
+
+        char *m = NULL;
+        sd_journal *j;
+        int r;
+        unsigned i;
+
+        assert(service);
+
+        if (n_columns <= 0)
+                n_columns = columns();
+
+        if (how_many <= 0)
+                how_many = 10;
+
+        if (!prefix)
+                prefix = "";
+
+        if (asprintf(&m, "_SYSTEMD_SERVICE=%s", service) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
+        if (r < 0)
+                goto finish;
+
+        r = sd_journal_add_match(j, m, strlen(m));
+        if (r < 0)
+                goto finish;
+
+        r = sd_journal_seek_tail(j);
+        if (r < 0)
+                goto finish;
+
+        for (i = 0; i < how_many; i++)
+                sd_journal_previous(j);
+
+        for (i = 0; i < how_many; i++) {
+
+                r = sd_journal_next(j);
+                if (r < 0)
+                        goto finish;
+
+                if (r == 0)
+                        break;
+
+                r = output_journal(j, mode, i+1, show_all);
+                if (r < 0)
+                        goto finish;
+        }
+
+finish:
+        if (m)
+                free(m);
+
+        if (j)
+                sd_journal_close(j);
+
+        return r;
+}
diff --git a/src/logs-show.h b/src/logs-show.h
new file mode 100644
index 0000000..f83df06
--- /dev/null
+++ b/src/logs-show.h
@@ -0,0 +1,49 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foologsshowhfoo
+#define foologsshowhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "sd-journal.h"
+#include "util.h"
+
+typedef enum output_mode {
+        OUTPUT_SHORT,
+        OUTPUT_VERBOSE,
+        OUTPUT_EXPORT,
+        OUTPUT_JSON,
+        _OUTPUT_MODE_MAX
+} output_mode;
+
+int output_journal(sd_journal *j, output_mode mode, unsigned line, bool show_all);
+
+int show_journal_by_service(
+                const char *service,
+                output_mode mode,
+                const char *prefix,
+                unsigned n_columns,
+                usec_t not_before,
+                unsigned how_many,
+                bool show_all);
+
+#endif
diff --git a/src/systemctl.c b/src/systemctl.c
index 1142200..10e3991 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -58,6 +58,7 @@
 #include "pager.h"
 #include "spawn-agent.h"
 #include "install.h"
+#include "logs-show.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
@@ -2261,6 +2262,9 @@ static void print_status_info(UnitStatusInfo *i) {
                 }
         }
 
+        if (i->id && arg_transport != TRANSPORT_SSH)
+                show_journal_by_service(i->id, OUTPUT_SHORT, NULL, 0, 0, 0, arg_all);
+
         if (i->need_daemon_reload)
                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
                        ansi_highlight(true),

commit adf7d506b50af9ba398a9925c8cd47ba328e720c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 21:07:12 2012 +0100

    journal: never fail if we cannot access /var, just print a warning

diff --git a/src/journal/journald.c b/src/journal/journald.c
index 5c8e713..1faf570 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -1196,12 +1196,10 @@ static int system_journal_open(Server *s) {
                         fix_perms(s->system_journal, 0);
                 } else if (r < 0) {
 
-                        if (r == -ENOENT || r == -EROFS)
-                                r = 0;
-                        else {
-                                log_error("Failed to open system journal: %s", strerror(-r));
-                                return r;
-                        }
+                        if (r != -ENOENT && r != -EROFS)
+                                log_warning("Failed to open system journal: %s", strerror(-r));
+
+                        r = 0;
                 }
         }
 
@@ -1221,13 +1219,10 @@ static int system_journal_open(Server *s) {
                         free(fn);
 
                         if (r < 0) {
+                                if (r != -ENOENT)
+                                        log_warning("Failed to open runtime journal: %s", strerror(-r));
 
-                                if (r == -ENOENT)
-                                        r = 0;
-                                else {
-                                        log_error("Failed to open runtime journal: %s", strerror(-r));
-                                        return r;
-                                }
+                                r = 0;
                         }
 
                 } else {

commit 52f4f45bf48cfb757024f9abf49f1533b661397a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 21:02:13 2012 +0100

    journald: treat a read-only /var identical to an unmounted one

diff --git a/Makefile.am b/Makefile.am
index 1af9cbc..8bb5b9d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1175,6 +1175,7 @@ systemd_journald_CFLAGS = \
 systemd_journald_LDADD = \
 	libsystemd-basic.la \
 	libsystemd-daemon.la \
+	libsystemd-login.la \
 	$(ACL_LIBS)
 
 if HAVE_XZ
diff --git a/src/journal/journald.c b/src/journal/journald.c
index 44c2aa4..5c8e713 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -1196,7 +1196,7 @@ static int system_journal_open(Server *s) {
                         fix_perms(s->system_journal, 0);
                 } else if (r < 0) {
 
-                        if (r == -ENOENT)
+                        if (r == -ENOENT || r == -EROFS)
                                 r = 0;
                         else {
                                 log_error("Failed to open system journal: %s", strerror(-r));

commit 85d83bf41c8bdf55c10b7f845d81e5787ef6c295
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 21:01:11 2012 +0100

    journald: add _SYSTEMD_SESSION, _SYSTEMD_OWNER_UID, _SYSTEMD_SERVICE to all entries

diff --git a/src/journal/journald.c b/src/journal/journald.c
index f637d94..44c2aa4 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -41,6 +41,7 @@
 #include "list.h"
 #include "journal-rate-limit.h"
 #include "sd-journal.h"
+#include "sd-login.h"
 #include "journal-internal.h"
 
 #define USER_JOURNALS_MAX 1024
@@ -423,7 +424,8 @@ static void dispatch_message_real(Server *s,
                 *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
                 *comm = NULL, *cmdline = NULL, *hostname = NULL,
                 *audit_session = NULL, *audit_loginuid = NULL,
-                *exe = NULL, *cgroup = NULL;
+                *exe = NULL, *cgroup = NULL, *session = NULL,
+                *owner_uid = NULL, *service = NULL;
 
         char idbuf[33];
         sd_id128_t id;
@@ -436,11 +438,11 @@ static void dispatch_message_real(Server *s,
         assert(s);
         assert(iovec);
         assert(n > 0);
-        assert(n + 13 <= m);
+        assert(n + 16 <= m);
 
         if (ucred) {
-                uint32_t session;
-                char *path;
+                uint32_t audit;
+                uid_t owner;
 
                 realuid = ucred->uid;
 
@@ -456,30 +458,33 @@ static void dispatch_message_real(Server *s,
                 r = get_process_comm(ucred->pid, &t);
                 if (r >= 0) {
                         comm = strappend("_COMM=", t);
+                        free(t);
+
                         if (comm)
                                 IOVEC_SET_STRING(iovec[n++], comm);
-                        free(t);
                 }
 
                 r = get_process_exe(ucred->pid, &t);
                 if (r >= 0) {
                         exe = strappend("_EXE=", t);
+                        free(t);
+
                         if (comm)
                                 IOVEC_SET_STRING(iovec[n++], exe);
-                        free(t);
                 }
 
                 r = get_process_cmdline(ucred->pid, LINE_MAX, false, &t);
                 if (r >= 0) {
                         cmdline = strappend("_CMDLINE=", t);
+                        free(t);
+
                         if (cmdline)
                                 IOVEC_SET_STRING(iovec[n++], cmdline);
-                        free(t);
                 }
 
-                r = audit_session_from_pid(ucred->pid, &session);
+                r = audit_session_from_pid(ucred->pid, &audit);
                 if (r >= 0)
-                        if (asprintf(&audit_session, "_AUDIT_SESSION=%lu", (unsigned long) session) >= 0)
+                        if (asprintf(&audit_session, "_AUDIT_SESSION=%lu", (unsigned long) audit) >= 0)
                                 IOVEC_SET_STRING(iovec[n++], audit_session);
 
                 r = audit_loginuid_from_pid(ucred->pid, &loginuid);
@@ -487,14 +492,34 @@ static void dispatch_message_real(Server *s,
                         if (asprintf(&audit_loginuid, "_AUDIT_LOGINUID=%lu", (unsigned long) loginuid) >= 0)
                                 IOVEC_SET_STRING(iovec[n++], audit_loginuid);
 
-                path = shortened_cgroup_path(ucred->pid);
-                if (path) {
-                        cgroup = strappend("_SYSTEMD_CGROUP=", path);
+                t = shortened_cgroup_path(ucred->pid);
+                if (t) {
+                        cgroup = strappend("_SYSTEMD_CGROUP=", t);
+                        free(t);
+
                         if (cgroup)
                                 IOVEC_SET_STRING(iovec[n++], cgroup);
+                }
+
+                if (sd_pid_get_session(ucred->pid, &t) >= 0) {
+                        session = strappend("_SYSTEMD_SESSION=", t);
+                        free(t);
+
+                        if (session)
+                                IOVEC_SET_STRING(iovec[n++], session);
+                }
 
-                        free(path);
+                if (sd_pid_get_service(ucred->pid, &t) >= 0) {
+                        service = strappend("_SYSTEMD_SERVICE=", t);
+                        free(t);
+
+                        if (service)
+                                IOVEC_SET_STRING(iovec[n++], service);
                 }
+
+                if (sd_pid_get_owner_uid(ucred->uid, &owner) >= 0)
+                        if (asprintf(&owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner) >= 0)
+                                IOVEC_SET_STRING(iovec[n++], owner_uid);
         }
 
         if (tv) {
@@ -519,9 +544,9 @@ static void dispatch_message_real(Server *s,
         t = gethostname_malloc();
         if (t) {
                 hostname = strappend("_HOSTNAME=", t);
+                free(t);
                 if (hostname)
                         IOVEC_SET_STRING(iovec[n++], hostname);
-                free(t);
         }
 
         assert(n <= m);
@@ -562,6 +587,9 @@ retry:
         free(audit_session);
         free(audit_loginuid);
         free(cgroup);
+        free(session);
+        free(owner_uid);
+        free(service);
 }
 
 static void dispatch_message(Server *s,
@@ -611,7 +639,7 @@ static void dispatch_message(Server *s,
         if (rl > 1) {
                 int j = 0;
                 char suppress_message[LINE_MAX];
-                struct iovec suppress_iovec[15];
+                struct iovec suppress_iovec[18];
 
                 /* Write a suppression message if we suppressed something */
 
@@ -632,7 +660,7 @@ finish:
 
 static void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv) {
         char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL;
-        struct iovec iovec[16];
+        struct iovec iovec[19];
         unsigned n = 0;
         int priority = LOG_USER | LOG_INFO;
 
@@ -739,11 +767,11 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_
 
                 /* A property follows */
 
-                if (n+13 >= m) {
+                if (n+16 >= m) {
                         struct iovec *c;
                         unsigned u;
 
-                        u = MAX((n+13U) * 2U, 4U);
+                        u = MAX((n+16U) * 2U, 4U);
                         c = realloc(iovec, u * sizeof(struct iovec));
                         if (!c) {
                                 log_error("Out of memory");
@@ -827,7 +855,7 @@ static void process_native_message(Server *s, const void *buffer, size_t buffer_
 }
 
 static int stdout_stream_log(StdoutStream *s, const char *p, size_t l) {
-        struct iovec iovec[15];
+        struct iovec iovec[18];
         char *message = NULL, *syslog_priority = NULL;
         unsigned n = 0;
         size_t tag_len;

commit 000a2c98860e4c1de7e1477bedf6ad216f8c5854
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 20:58:07 2012 +0100

    sd-id128: add _public_ to all exports, and add validity checks for all parameters

diff --git a/Makefile.am b/Makefile.am
index 651b37d..1af9cbc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1925,7 +1925,7 @@ man/sd_login_monitor_get_fd.3: man/sd_login_monitor_new.3
 man/sd_session_get_uid.3: man/sd_session_is_active.3
 man/sd_session_get_seat.3: man/sd_session_is_active.3
 man/sd_pid_get_owner_uid.3: man/sd_pid_get_session.3
-man/sd_pid_get_session.3: man/sd_pid_get_session.3
+man/sd_pid_get_service.3: man/sd_pid_get_session.3
 man/sd_uid_is_on_seat.3: man/sd_uid_get_state.3
 man/sd_uid_get_sessions.3: man/sd_uid_get_state.3
 man/sd_uid_get_seats.3: man/sd_uid_get_state.3
diff --git a/src/sd-id128.c b/src/sd-id128.c
index f5e0432..387cf91 100644
--- a/src/sd-id128.c
+++ b/src/sd-id128.c
@@ -27,10 +27,11 @@
 #include "util.h"
 #include "macro.h"
 
-char *sd_id128_to_string(sd_id128_t id, char s[33]) {
+_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
         unsigned n;
 
-        assert(s);
+        if (!s)
+                return NULL;
 
         for (n = 0; n < 16; n++) {
                 s[n*2] = hexchar(id.bytes[n] >> 4);
@@ -42,12 +43,14 @@ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
         return s;
 }
 
-int sd_id128_from_string(const char s[33], sd_id128_t *ret) {
+_public_ int sd_id128_from_string(const char s[33], sd_id128_t *ret) {
         unsigned n;
         sd_id128_t t;
 
-        assert(s);
-        assert(ret);
+        if (!s)
+                return -EINVAL;
+        if (!ret)
+                return -EINVAL;
 
         for (n = 0; n < 16; n++) {
                 int a, b;
@@ -70,7 +73,7 @@ int sd_id128_from_string(const char s[33], sd_id128_t *ret) {
         return 0;
 }
 
-sd_id128_t sd_id128_make_v4_uuid(sd_id128_t id) {
+_public_ sd_id128_t sd_id128_make_v4_uuid(sd_id128_t id) {
         /* Stolen from generate_random_uuid() of drivers/char/random.c
          * in the kernel sources */
 
@@ -83,7 +86,7 @@ sd_id128_t sd_id128_make_v4_uuid(sd_id128_t id) {
         return id;
 }
 
-int sd_id128_get_machine(sd_id128_t *ret) {
+_public_ int sd_id128_get_machine(sd_id128_t *ret) {
         static __thread sd_id128_t saved_machine_id;
         static __thread bool saved_machine_id_valid = false;
         int fd;
@@ -92,6 +95,9 @@ int sd_id128_get_machine(sd_id128_t *ret) {
         unsigned j;
         sd_id128_t t;
 
+        if (!ret)
+                return -EINVAL;
+
         if (saved_machine_id_valid) {
                 *ret = saved_machine_id;
                 return 0;
@@ -129,7 +135,7 @@ int sd_id128_get_machine(sd_id128_t *ret) {
         return 0;
 }
 
-int sd_id128_get_boot(sd_id128_t *ret) {
+_public_ int sd_id128_get_boot(sd_id128_t *ret) {
         static __thread sd_id128_t saved_boot_id;
         static __thread bool saved_boot_id_valid = false;
         int fd;
@@ -139,6 +145,9 @@ int sd_id128_get_boot(sd_id128_t *ret) {
         sd_id128_t t;
         char *p;
 
+        if (!ret)
+                return -EINVAL;
+
         if (saved_boot_id_valid) {
                 *ret = saved_boot_id;
                 return 0;
@@ -181,12 +190,13 @@ int sd_id128_get_boot(sd_id128_t *ret) {
         return 0;
 }
 
-int sd_id128_randomize(sd_id128_t *ret) {
+_public_ int sd_id128_randomize(sd_id128_t *ret) {
         int fd;
         ssize_t k;
         sd_id128_t t;
 
-        assert(ret);
+        if (!ret)
+                return -EINVAL;
 
         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0)

commit a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 20:54:15 2012 +0100

    journal: add _public_ to all sd-journal calls, and add parameter checks

diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index cc3cd8c..db5dbc0 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -53,7 +53,7 @@ retry:
         return fd;
 }
 
-int sd_journal_print(int priority, const char *format, ...) {
+_public_ int sd_journal_print(int priority, const char *format, ...) {
         int r;
         va_list ap;
 
@@ -64,7 +64,7 @@ int sd_journal_print(int priority, const char *format, ...) {
         return r;
 }
 
-int sd_journal_printv(int priority, const char *format, va_list ap) {
+_public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
         char buffer[8 + LINE_MAX], p[11];
         struct iovec iov[2];
 
@@ -88,7 +88,7 @@ int sd_journal_printv(int priority, const char *format, va_list ap) {
         return sd_journal_sendv(iov, 2);
 }
 
-int sd_journal_send(const char *format, ...) {
+_public_ int sd_journal_send(const char *format, ...) {
         int r, n = 0, i = 0, j;
         va_list ap;
         struct iovec *iov = NULL;
@@ -131,7 +131,7 @@ fail:
         return r;
 }
 
-int sd_journal_sendv(const struct iovec *iov, int n) {
+_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
         int fd;
         struct iovec *w;
         uint64_t *l;
@@ -148,8 +148,12 @@ int sd_journal_sendv(const struct iovec *iov, int n) {
         for (i = 0; i < n; i++) {
                 char *c, *nl;
 
+                if (!iov[i].iov_base ||
+                    iov[i].iov_len <= 1)
+                        return -EINVAL;
+
                 c = memchr(iov[i].iov_base, '=', iov[i].iov_len);
-                if (!c)
+                if (!c || c == iov[i].iov_base)
                         return -EINVAL;
 
                 nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len);
@@ -205,7 +209,7 @@ int sd_journal_sendv(const struct iovec *iov, int n) {
         return 0;
 }
 
-int sd_journal_stream_fd(const char *tag, int priority, int priority_prefix) {
+_public_ int sd_journal_stream_fd(const char *tag, int priority, int priority_prefix) {
         union sockaddr_union sa;
         int fd;
         char *header;
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 38e58f5..bb3b0ae 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -106,17 +106,17 @@ static int same_field(const void *_a, size_t s, const void *_b, size_t t) {
         return -EINVAL;
 }
 
-int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
+_public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
         Match *m, *after = NULL;
         uint64_t le_hash;
 
-        assert(j);
-
+        if (!j)
+                return -EINVAL;
+        if (!data)
+                return -EINVAL;
         if (size <= 0)
                 return -EINVAL;
 
-        assert(data);
-
         le_hash = htole64(hash64(data, size));
 
         LIST_FOREACH(matches, m, j->matches) {
@@ -159,8 +159,9 @@ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
         return 0;
 }
 
-void sd_journal_flush_matches(sd_journal *j) {
-        assert(j);
+_public_ void sd_journal_flush_matches(sd_journal *j) {
+        if (!j)
+                return;
 
         while (j->matches) {
                 Match *m = j->matches;
@@ -626,7 +627,8 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
         uint64_t new_offset = 0;
         Object *new_entry = NULL;
 
-        assert(j);
+        if (!j)
+                return -EINVAL;
 
         HASHMAP_FOREACH(f, j->files, i) {
                 Object *o;
@@ -667,18 +669,19 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
         return 1;
 }
 
-int sd_journal_next(sd_journal *j) {
+_public_ int sd_journal_next(sd_journal *j) {
         return real_journal_next(j, DIRECTION_DOWN);
 }
 
-int sd_journal_previous(sd_journal *j) {
+_public_ int sd_journal_previous(sd_journal *j) {
         return real_journal_next(j, DIRECTION_UP);
 }
 
-int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
+_public_ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
         int c = 0, r;
 
-        assert(j);
+        if (!j)
+                return -EINVAL;
 
         while (skip > 0) {
                 r = sd_journal_next(j);
@@ -695,10 +698,11 @@ int sd_journal_next_skip(sd_journal *j, uint64_t skip) {
         return c;
 }
 
-int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
+_public_ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
         int c = 0, r;
 
-        assert(j);
+        if (!j)
+                return -EINVAL;
 
         while (skip > 0) {
                 r = sd_journal_previous(j);
@@ -715,13 +719,15 @@ int sd_journal_previous_skip(sd_journal *j, uint64_t skip) {
         return 1;
 }
 
-int sd_journal_get_cursor(sd_journal *j, char **cursor) {
+_public_ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
         Object *o;
         int r;
         char bid[33], sid[33];
 
-        assert(j);
-        assert(cursor);
+        if (!j)
+                return -EINVAL;
+        if (!cursor)
+                return -EINVAL;
 
         if (!j->current_file || j->current_file->current_offset <= 0)
                 return -EADDRNOTAVAIL;
@@ -745,7 +751,7 @@ int sd_journal_get_cursor(sd_journal *j, char **cursor) {
         return 1;
 }
 
-int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
+_public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
         char *w;
         size_t l;
         char *state;
@@ -759,8 +765,10 @@ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
                 xor_hash_set = false;
         sd_id128_t seqnum_id, boot_id;
 
-        assert(j);
-        assert(cursor);
+        if (!j)
+                return -EINVAL;
+        if (!cursor)
+                return -EINVAL;
 
         FOREACH_WORD_SEPARATOR(w, l, cursor, ";", state) {
                 char *item;
@@ -850,8 +858,9 @@ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
         return 0;
 }
 
-int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
-        assert(j);
+_public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t usec) {
+        if (!j)
+                return -EINVAL;
 
         reset_location(j);
         j->current_location.type = LOCATION_DISCRETE;
@@ -862,8 +871,9 @@ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, uint64_t u
         return 0;
 }
 
-int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
-        assert(j);
+_public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
+        if (!j)
+                return -EINVAL;
 
         reset_location(j);
         j->current_location.type = LOCATION_DISCRETE;
@@ -873,8 +883,9 @@ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
         return 0;
 }
 
-int sd_journal_seek_head(sd_journal *j) {
-        assert(j);
+_public_ int sd_journal_seek_head(sd_journal *j) {
+        if (!j)
+                return -EINVAL;
 
         reset_location(j);
         j->current_location.type = LOCATION_HEAD;
@@ -882,8 +893,9 @@ int sd_journal_seek_head(sd_journal *j) {
         return 0;
 }
 
-int sd_journal_seek_tail(sd_journal *j) {
-        assert(j);
+_public_ int sd_journal_seek_tail(sd_journal *j) {
+        if (!j)
+                return -EINVAL;
 
         reset_location(j);
         j->current_location.type = LOCATION_TAIL;
@@ -1095,7 +1107,7 @@ static void remove_root_wd(sd_journal *j, int wd) {
         }
 }
 
-int sd_journal_open(sd_journal **ret, int flags) {
+_public_ int sd_journal_open(sd_journal **ret, int flags) {
         sd_journal *j;
         const char *p;
         const char search_paths[] =
@@ -1103,7 +1115,13 @@ int sd_journal_open(sd_journal **ret, int flags) {
                 "/var/log/journal\0";
         int r;
 
-        assert(ret);
+        if (!ret)
+                return -EINVAL;
+
+        if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
+                      SD_JOURNAL_RUNTIME_ONLY|
+                      SD_JOURNAL_SYSTEM_ONLY))
+                return -EINVAL;
 
         j = new0(sd_journal, 1);
         if (!j)
@@ -1184,8 +1202,9 @@ fail:
         return r;
 };
 
-void sd_journal_close(sd_journal *j) {
-        assert(j);
+_public_ void sd_journal_close(sd_journal *j) {
+        if (!j)
+                return;
 
         if (j->inotify_wd_dirs) {
                 void *k;
@@ -1222,13 +1241,15 @@ void sd_journal_close(sd_journal *j) {
         free(j);
 }
 
-int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
+_public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
         Object *o;
         JournalFile *f;
         int r;
 
-        assert(j);
-        assert(ret);
+        if (!j)
+                return -EINVAL;
+        if (!ret)
+                return -EINVAL;
 
         f = j->current_file;
         if (!f)
@@ -1245,14 +1266,16 @@ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
         return 0;
 }
 
-int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
+_public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_boot_id) {
         Object *o;
         JournalFile *f;
         int r;
         sd_id128_t id;
 
-        assert(j);
-        assert(ret);
+        if (!j)
+                return -EINVAL;
+        if (!ret)
+                return -EINVAL;
 
         f = j->current_file;
         if (!f)
@@ -1280,17 +1303,21 @@ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id128_t *ret_
         return 0;
 }
 
-int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
+_public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, size_t *size) {
         JournalFile *f;
         uint64_t i, n;
         size_t field_length;
         int r;
         Object *o;
 
-        assert(j);
-        assert(field);
-        assert(data);
-        assert(size);
+        if (!j)
+                return -EINVAL;
+        if (!field)
+                return -EINVAL;
+        if (!data)
+                return -EINVAL;
+        if (!size)
+                return -EINVAL;
 
         if (isempty(field) || strchr(field, '='))
                 return -EINVAL;
@@ -1369,16 +1396,19 @@ int sd_journal_get_data(sd_journal *j, const char *field, const void **data, siz
         return -ENOENT;
 }
 
-int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
+_public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
         JournalFile *f;
         uint64_t p, l, n, le_hash;
         int r;
         Object *o;
         size_t t;
 
-        assert(j);
-        assert(data);
-        assert(size);
+        if (!j)
+                return -EINVAL;
+        if (!data)
+                return -EINVAL;
+        if (!size)
+                return -EINVAL;
 
         f = j->current_file;
         if (!f)
@@ -1433,14 +1463,16 @@ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
         return 1;
 }
 
-void sd_journal_restart_data(sd_journal *j) {
-        assert(j);
+_public_ void sd_journal_restart_data(sd_journal *j) {
+        if (!j)
+                return;
 
         j->current_field = 0;
 }
 
-int sd_journal_get_fd(sd_journal *j) {
-        assert(j);
+_public_ int sd_journal_get_fd(sd_journal *j) {
+        if (!j)
+                return -EINVAL;
 
         return j->inotify_fd;
 }
@@ -1523,10 +1555,11 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
         log_warning("Unknown inotify event.");
 }
 
-int sd_journal_process(sd_journal *j) {
+_public_ int sd_journal_process(sd_journal *j) {
         uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX];
 
-        assert(j);
+        if (!j)
+                return -EINVAL;
 
         for (;;) {
                 struct inotify_event *e;
@@ -1555,19 +1588,27 @@ int sd_journal_process(sd_journal *j) {
         }
 }
 
-int sd_journal_query_unique(sd_journal *j, const char *field) {
-        assert(j);
-        assert(field);
+_public_ int sd_journal_query_unique(sd_journal *j, const char *field) {
+        if (!j)
+                return -EINVAL;
+        if (!field)
+                return -EINVAL;
 
         return -ENOTSUP;
 }
 
-int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
-        assert(j);
+_public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l) {
+        if (!j)
+                return -EINVAL;
+        if (!data)
+                return -EINVAL;
+        if (!l)
+                return -EINVAL;
 
         return -ENOTSUP;
 }
 
-void sd_journal_restart_unique(sd_journal *j) {
-        assert(j);
+_public_ void sd_journal_restart_unique(sd_journal *j) {
+        if (!j)
+                return;
 }
diff --git a/src/journal/sd-journal.h b/src/journal/sd-journal.h
index 97f9f0f..d7e2528 100644
--- a/src/journal/sd-journal.h
+++ b/src/journal/sd-journal.h
@@ -31,12 +31,12 @@
 
 /* TODO:
  *
+ *   - add options for copy-to-console, copy-to-kmsg
  *   - OR of matches is borked...
  *   - extend hash tables table as we go
  *   - accelerate looking for "all hostnames" and suchlike.
  *   - hookup with systemctl
  *   - handle incomplete header
- *   - write unit files
  *
  *   - local deserializer
  *   - http server

commit 9847946e12479b27d3ebfd024f00a6ac33ce73d3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 20:51:38 2012 +0100

    login: introduce sd_pid_get_service()

diff --git a/Makefile.am b/Makefile.am
index 225c6fc..651b37d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,9 +20,9 @@ ACLOCAL_AMFLAGS = -I m4
 
 SUBDIRS = po
 
-LIBSYSTEMD_LOGIN_CURRENT=0
-LIBSYSTEMD_LOGIN_REVISION=6
-LIBSYSTEMD_LOGIN_AGE=0
+LIBSYSTEMD_LOGIN_CURRENT=1
+LIBSYSTEMD_LOGIN_REVISION=0
+LIBSYSTEMD_LOGIN_AGE=1
 
 LIBSYSTEMD_DAEMON_CURRENT=0
 LIBSYSTEMD_DAEMON_REVISION=0
@@ -1910,6 +1910,7 @@ MANPAGES_ALIAS += \
 	man/sd_session_get_uid.3 \
 	man/sd_session_get_seat.3 \
 	man/sd_pid_get_owner_uid.3 \
+	man/sd_pid_get_service.3 \
 	man/sd_uid_is_on_seat.3 \
 	man/sd_uid_get_sessions.3 \
 	man/sd_uid_get_seats.3 \
@@ -1924,6 +1925,7 @@ man/sd_login_monitor_get_fd.3: man/sd_login_monitor_new.3
 man/sd_session_get_uid.3: man/sd_session_is_active.3
 man/sd_session_get_seat.3: man/sd_session_is_active.3
 man/sd_pid_get_owner_uid.3: man/sd_pid_get_session.3
+man/sd_pid_get_session.3: man/sd_pid_get_session.3
 man/sd_uid_is_on_seat.3: man/sd_uid_get_state.3
 man/sd_uid_get_sessions.3: man/sd_uid_get_state.3
 man/sd_uid_get_seats.3: man/sd_uid_get_state.3
diff --git a/man/sd_pid_get_session.xml b/man/sd_pid_get_session.xml
index 24e4680..4086c5a 100644
--- a/man/sd_pid_get_session.xml
+++ b/man/sd_pid_get_session.xml
@@ -44,8 +44,9 @@
 
         <refnamediv>
                 <refname>sd_pid_get_session</refname>
+                <refname>sd_pid_get_service</refname>
                 <refname>sd_pid_get_owner_uid</refname>
-                <refpurpose>Determine session or owner of a session of a specific PID</refpurpose>
+                <refpurpose>Determine session, service or owner of a session of a specific PID</refpurpose>
         </refnamediv>
 
         <refsynopsisdiv>
@@ -59,6 +60,12 @@
                         </funcprototype>
 
                         <funcprototype>
+                                <funcdef>int <function>sd_pid_get_service</function></funcdef>
+                                <paramdef>pid_t <parameter>pid</parameter></paramdef>
+                                <paramdef>char** <parameter>service</parameter></paramdef>
+                        </funcprototype>
+
+                        <funcprototype>
                                 <funcdef>int <function>sd_pid_get_owner_uid</function></funcdef>
                                 <paramdef>pid_t <parameter>pid</parameter></paramdef>
                                 <paramdef>uid_t* <parameter>uid</parameter></paramdef>
@@ -75,11 +82,23 @@
                 identifier. The session identifier is a short string,
                 suitable for usage in file system paths. Note that not
                 all processes are part of a login session (e.g. system
-                service processes and user processes that are shared
-                between multiple sessions of the same user). For
-                processes not being part of a login session this
-                function will fail. The returned string needs to be
-                freed with the libc
+                service processes, user processes that are shared
+                between multiple sessions of the same user, or kernel
+                threads). For processes not being part of a login
+                session this function will fail. The returned string
+                needs to be freed with the libc
+                <citerefentry><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+                call after use.</para>
+
+                <para><function>sd_pid_get_service()</function> may be
+                used to determine the system service identifier of a
+                process identified by the specified process
+                identifier. The service name is a short string,
+                suitable for usage in file system paths. Note that not
+                all processes are part of a service (e.g. user
+                processes, or kernel threads). For processes not being
+                part of a system service this function will fail. The
+                returned string needs to be freed with the libc
                 <citerefentry><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
                 call after use.</para>
 
@@ -106,10 +125,11 @@
         <refsect1>
                 <title>Notes</title>
 
-                <para>The <function>sd_pid_get_session()</function>
-                and <function>sd_pid_get_owner_uid()</function>
-                interfaces are available as shared library, which can
-                be compiled and linked to with the
+                <para>The <function>sd_pid_get_session()</function>,
+                <function>sd_pid_get_service()</function>, and
+                <function>sd_pid_get_owner_uid()</function> interfaces
+                are available as shared library, which can be compiled
+                and linked to with the
                 <literal>libsystemd-login</literal>
                 <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 file.</para>
diff --git a/src/login/libsystemd-login.sym b/src/login/libsystemd-login.sym
index 0d51fa7..bac46f4 100644
--- a/src/login/libsystemd-login.sym
+++ b/src/login/libsystemd-login.sym
@@ -33,3 +33,8 @@ global:
 local:
         *;
 };
+
+LIBSYSTEMD_LOGIN_38 {
+global:
+        sd_pid_get_service;
+} LIBSYSTEMD_LOGIN_31;
diff --git a/src/login/sd-login.c b/src/login/sd-login.c
index a0a56c4..1d43681 100644
--- a/src/login/sd-login.c
+++ b/src/login/sd-login.c
@@ -121,6 +121,33 @@ _public_ int sd_pid_get_session(pid_t pid, char **session) {
         return 0;
 }
 
+_public_ int sd_pid_get_service(pid_t pid, char **service) {
+        int r;
+        char *cgroup, *p;
+
+        if (!service)
+                return -EINVAL;
+
+        r = pid_get_cgroup(pid, NULL, &cgroup);
+        if (r < 0)
+                return r;
+
+        if (!startswith(cgroup, "/system/")) {
+                free(cgroup);
+                return -ENOENT;
+        }
+
+        p = cgroup + 8;
+        p = strndup(p, strcspn(p, "/"));
+        free(cgroup);
+
+        if (!p)
+                return -ENOMEM;
+
+        *service = p;
+        return 0;
+}
+
 _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
         int r;
         char *root, *cgroup, *p, *cc;
diff --git a/src/login/sd-login.h b/src/login/sd-login.h
index 0cb0bf0..1d8a55e 100644
--- a/src/login/sd-login.h
+++ b/src/login/sd-login.h
@@ -53,6 +53,10 @@ int sd_pid_get_session(pid_t pid, char **session);
  * return an error for system processes. */
 int sd_pid_get_owner_uid(pid_t pid, uid_t *uid);
 
+/* Get service name from PID. This will return an error for
+ * non-service processes. */
+int sd_pid_get_service(pid_t, char **service);
+
 /* Get state from uid. Possible states: offline, lingering, online, active */
 int sd_uid_get_state(uid_t uid, char**state);
 

commit b72491a2fd8c237299055c636d4f748bca2b4b1f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 20:41:20 2012 +0100

    nspawn: get rid of BUFFER_SIZE, use LINE_MAX instead

diff --git a/src/nspawn.c b/src/nspawn.c
index 653d7db..3ea603f 100644
--- a/src/nspawn.c
+++ b/src/nspawn.c
@@ -394,11 +394,9 @@ static int is_os_tree(const char *path) {
         return r < 0 ? 0 : 1;
 }
 
-#define BUFFER_SIZE 1024
-
 static int process_pty(int master, sigset_t *mask) {
 
-        char in_buffer[BUFFER_SIZE], out_buffer[BUFFER_SIZE];
+        char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
         size_t in_buffer_full = 0, out_buffer_full = 0;
         struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
         bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
@@ -519,9 +517,9 @@ static int process_pty(int master, sigset_t *mask) {
                        (master_readable && out_buffer_full <= 0) ||
                        (stdout_writable && out_buffer_full > 0)) {
 
-                        if (stdin_readable && in_buffer_full < BUFFER_SIZE) {
+                        if (stdin_readable && in_buffer_full < LINE_MAX) {
 
-                                if ((k = read(STDIN_FILENO, in_buffer + in_buffer_full, BUFFER_SIZE - in_buffer_full)) < 0) {
+                                if ((k = read(STDIN_FILENO, in_buffer + in_buffer_full, LINE_MAX - in_buffer_full)) < 0) {
 
                                         if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
                                                 stdin_readable = false;
@@ -553,9 +551,9 @@ static int process_pty(int master, sigset_t *mask) {
                                 }
                         }
 
-                        if (master_readable && out_buffer_full < BUFFER_SIZE) {
+                        if (master_readable && out_buffer_full < LINE_MAX) {
 
-                                if ((k = read(master, out_buffer + out_buffer_full, BUFFER_SIZE - out_buffer_full)) < 0) {
+                                if ((k = read(master, out_buffer + out_buffer_full, LINE_MAX - out_buffer_full)) < 0) {
 
                                         if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
                                                 master_readable = false;

commit 4f3656e1cec7fe3d7d3537e23a406cb88d734502
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 20:34:09 2012 +0100

    readahead: bring export definition of sd-readahead in line with sd-daemon

diff --git a/src/readahead/sd-readahead.c b/src/readahead/sd-readahead.c
index c5cfe67..a334066 100644
--- a/src/readahead/sd-readahead.c
+++ b/src/readahead/sd-readahead.c
@@ -37,6 +37,18 @@
 
 #include "sd-readahead.h"
 
+#if (__GNUC__ >= 4)
+#ifdef SD_EXPORT_SYMBOLS
+/* Export symbols */
+#define _sd_export_ __attribute__ ((visibility("default")))
+#else
+/* Don't export the symbols */
+#define _sd_export_ __attribute__ ((visibility("hidden")))
+#endif
+#else
+#define _sd_export_
+#endif
+
 static int touch(const char *path) {
 
 #if !defined(DISABLE_SYSTEMD) && defined(__linux__)
@@ -60,7 +72,7 @@ static int touch(const char *path) {
         return 0;
 }
 
-int sd_readahead(const char *action) {
+_sd_export_ int sd_readahead(const char *action) {
 
         if (!action)
                 return -EINVAL;
diff --git a/src/readahead/sd-readahead.h b/src/readahead/sd-readahead.h
index 5bf975a..ee7e306 100644
--- a/src/readahead/sd-readahead.h
+++ b/src/readahead/sd-readahead.h
@@ -56,14 +56,6 @@ extern "C" {
   See sd-readahead(7) for more information.
 */
 
-#ifndef _sd_hidden_
-#if (__GNUC__ >= 4) && !defined(SD_EXPORT_SYMBOLS)
-#define _sd_hidden_ __attribute__ ((visibility("hidden")))
-#else
-#define _sd_hidden_
-#endif
-#endif
-
 /*
   Controls ongoing disk read-ahead operations during boot-up. The argument
   must be a string, and either "cancel", "done" or "noreplay".
@@ -72,7 +64,7 @@ extern "C" {
   done = terminate read-ahead data collection, keep collected information
   noreplay = terminate read-ahead replay
 */
-int sd_readahead(const char *action) _sd_hidden_;
+int sd_readahead(const char *action);
 
 #ifdef __cplusplus
 }

commit 4cfc6dbe52e4ff867750ce0d64f09d42c0ea6c27
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Jan 3 20:33:28 2012 +0100

    socket: only add dependency on kmsg socket to socket units which have any kind of exec program specified

diff --git a/src/socket.c b/src/socket.c
index bbfc842..1f5e067 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -323,6 +323,17 @@ static int socket_add_default_dependencies(Socket *s) {
         return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
 }
 
+static bool socket_has_exec(Socket *s) {
+        unsigned i;
+        assert(s);
+
+        for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++)
+                if (s->exec_command[i])
+                        return true;
+
+        return false;
+}
+
 static int socket_load(Unit *u) {
         Socket *s = SOCKET(u);
         int r;
@@ -352,8 +363,9 @@ static int socket_load(Unit *u) {
                 if ((r = socket_add_device_link(s)) < 0)
                         return r;
 
-                if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
-                        return r;
+                if (socket_has_exec(s))
+                        if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
+                                return r;
 
                 if ((r = unit_add_default_cgroups(u)) < 0)
                         return r;

commit 4de856120f252e7aa19c923c10fbf23310d623aa
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jan 2 17:07:00 2012 +0100

    build-sys: make quotacheck and randomseed optional

diff --git a/Makefile.am b/Makefile.am
index b55e0b9..225c6fc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -182,7 +182,6 @@ rootlibexec_PROGRAMS = \
 	systemd-cgroups-agent \
 	systemd-initctl \
 	systemd-update-utmp \
-	systemd-random-seed \
 	systemd-shutdownd \
 	systemd-shutdown \
 	systemd-modules-load \
@@ -190,7 +189,6 @@ rootlibexec_PROGRAMS = \
 	systemd-kmsg-syslogd \
 	systemd-reply-password \
 	systemd-fsck \
-	systemd-quotacheck \
 	systemd-timestamp \
 	systemd-ac-power \
 	systemd-detect-virt \
@@ -325,8 +323,6 @@ nodist_systemunit_DATA = \
 	units/systemd-remount-api-vfs.service \
 	units/systemd-update-utmp-runlevel.service \
 	units/systemd-update-utmp-shutdown.service \
-	units/systemd-random-seed-save.service \
-	units/systemd-random-seed-load.service \
 	units/systemd-tmpfiles-setup.service \
 	units/systemd-tmpfiles-clean.service \
 	units/systemd-ask-password-wall.service \
@@ -338,7 +334,6 @@ nodist_systemunit_DATA = \
 	units/kexec.service \
 	units/fsck at .service \
 	units/fsck-root.service \
-	units/quotacheck.service \
 	units/rescue.service \
 	units/user at .service
 
@@ -362,8 +357,6 @@ EXTRA_DIST += \
 	units/systemd-remount-api-vfs.service.in \
 	units/systemd-update-utmp-runlevel.service.in \
 	units/systemd-update-utmp-shutdown.service.in \
-	units/systemd-random-seed-save.service.in \
-	units/systemd-random-seed-load.service.in \
 	units/systemd-tmpfiles-setup.service.in \
 	units/systemd-tmpfiles-clean.service.in \
 	units/systemd-ask-password-wall.service.in \
@@ -376,7 +369,6 @@ EXTRA_DIST += \
 	units/user/exit.service.in \
 	units/fsck at .service.in \
 	units/fsck-root.service.in \
-	units/quotacheck.service.in \
 	units/user at .service.in \
 	systemd.pc.in \
 	introspect.awk \
@@ -792,12 +784,6 @@ systemd_update_utmp_LDADD = \
 	$(DBUS_LIBS) \
 	$(AUDIT_LIBS)
 
-systemd_random_seed_SOURCES = \
-	src/random-seed.c
-
-systemd_random_seed_LDADD = \
-	libsystemd-basic.la
-
 systemd_shutdownd_SOURCES = \
 	src/utmp-wtmp.c \
 	src/shutdownd.c
@@ -862,12 +848,6 @@ systemd_fsck_LDADD = \
 	$(UDEV_LIBS) \
 	$(DBUS_LIBS)
 
-systemd_quotacheck_SOURCES = \
-	src/quotacheck.c
-
-systemd_quotacheck_LDADD = \
-	libsystemd-basic.la
-
 systemd_timestamp_SOURCES = \
 	src/timestamp.c
 
@@ -1452,6 +1432,55 @@ MANPAGES += \
 endif
 
 # ------------------------------------------------------------------------------
+if ENABLE_QUOTACHECK
+rootlibexec_PROGRAMS += \
+	systemd-quotacheck
+
+nodist_systemunit_DATA += \
+	units/quotacheck.service
+
+EXTRA_DIST += \
+	units/quotacheck.service.in
+
+systemd_quotacheck_SOURCES = \
+	src/quotacheck.c
+
+systemd_quotacheck_LDADD = \
+	libsystemd-basic.la
+endif
+
+# ------------------------------------------------------------------------------
+if ENABLE_RANDOMSEED
+rootlibexec_PROGRAMS += \
+	systemd-random-seed
+
+nodist_systemunit_DATA += \
+	units/systemd-random-seed-save.service \
+	units/systemd-random-seed-load.service
+
+EXTRA_DIST += \
+	units/systemd-random-seed-save.service.in \
+	units/systemd-random-seed-load.service.in
+
+systemd_random_seed_SOURCES = \
+	src/random-seed.c
+
+systemd_random_seed_LDADD = \
+	libsystemd-basic.la
+
+randomseed-install-data-hook:
+	( cd $(DESTDIR)$(systemunitdir)/shutdown.target.wants && \
+		rm -f systemd-random-seed-save.service && \
+		$(LN_S) ../systemd-random-seed-save.service systemd-random-seed-save.service )
+	( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \
+		rm -f systemd-random-seed-load.service && \
+		$(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service )
+
+INSTALL_DATA_HOOKS += \
+	randomseed-install-data-hook
+endif
+
+# ------------------------------------------------------------------------------
 if HAVE_LIBCRYPTSETUP
 rootlibexec_PROGRAMS += \
 	systemd-cryptsetup
@@ -2137,10 +2166,8 @@ systemd-install-data-hook:
 		rm -f systemd-update-utmp-runlevel.service && \
 		$(LN_S) ../systemd-update-utmp-runlevel.service systemd-update-utmp-runlevel.service )
 	( cd $(DESTDIR)$(systemunitdir)/shutdown.target.wants && \
-		rm -f systemd-update-utmp-shutdown.service \
-			systemd-random-seed-save.service && \
-		$(LN_S) ../systemd-update-utmp-shutdown.service systemd-update-utmp-shutdown.service && \
-		$(LN_S) ../systemd-random-seed-save.service systemd-random-seed-save.service )
+		rm -f systemd-update-utmp-shutdown.service && \
+		$(LN_S) ../systemd-update-utmp-shutdown.service systemd-update-utmp-shutdown.service )
 	( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \
 		rm -f systemd-remount-api-vfs.service \
 			fsck-root.service \
@@ -2191,7 +2218,6 @@ systemd-install-data-hook:
 			sys-kernel-security.mount \
 			sys-fs-fuse-connections.mount \
 			systemd-modules-load.service \
-			systemd-random-seed-load.service \
 			systemd-tmpfiles-setup.service \
 			systemd-sysctl.service \
 			systemd-ask-password-console.path \
@@ -2203,7 +2229,6 @@ systemd-install-data-hook:
 		$(LN_S) ../sys-kernel-security.mount sys-kernel-security.mount && \
 		$(LN_S) ../sys-fs-fuse-connections.mount sys-fs-fuse-connections.mount && \
 		$(LN_S) ../systemd-modules-load.service systemd-modules-load.service && \
-		$(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service && \
 		$(LN_S) ../systemd-tmpfiles-setup.service systemd-tmpfiles-setup.service && \
 		$(LN_S) ../systemd-sysctl.service systemd-sysctl.service && \
 		$(LN_S) ../systemd-ask-password-console.path systemd-ask-password-console.path && \
diff --git a/configure.ac b/configure.ac
index 9f03f63..0316ad1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -330,6 +330,20 @@ if test "x$enable_readahead" != "xno"; then
 fi
 AM_CONDITIONAL(ENABLE_READAHEAD, [test "$have_readahead" = "yes"])
 
+have_quotacheck=no
+AC_ARG_ENABLE(quotacheck, AS_HELP_STRING([--disable-quotacheck], [disable quotacheck tools]))
+if test "x$enable_quotacheck" != "xno"; then
+	have_quotacheck=yes
+fi
+AM_CONDITIONAL(ENABLE_QUOTACHECK, [test "$have_quotacheck" = "yes"])
+
+have_randomseed=no
+AC_ARG_ENABLE(randomseed, AS_HELP_STRING([--disable-randomseed], [disable randomseed tools]))
+if test "x$enable_randomseed" != "xno"; then
+	have_randomseed=yes
+fi
+AM_CONDITIONAL(ENABLE_RANDOMSEED, [test "$have_randomseed" = "yes"])
+
 have_logind=no
 AC_ARG_ENABLE(logind, AS_HELP_STRING([--disable-logind], [disable login daemon]))
 if test "x$enable_logind" != "xno"; then
@@ -627,6 +641,8 @@ AC_MSG_RESULT([
         binfmt:                  ${have_binfmt}
         vconsole:                ${have_vconsole}
         readahead:               ${have_readahead}
+        quotacheck:              ${have_quotacheck}
+        randomseed:              ${have_randomseed}
         logind:                  ${have_logind}
         hostnamed:               ${have_hostnamed}
         timedated:               ${have_timedated}

commit 776a564f54dd54c7c4e2b2d865e8f9e7ee5404f3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jan 2 16:50:03 2012 +0100

    build-sys: move kbd-model-map to locale/

diff --git a/Makefile.am b/Makefile.am
index 0c3e970..b55e0b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -809,12 +809,6 @@ systemd_shutdownd_LDADD = \
 	libsystemd-basic.la \
 	libsystemd-daemon.la
 
-dist_pkgdata_DATA = \
-	src/kbd-model-map
-
-dist_noinst_SCRIPT = \
-	src/generate-kbd-model-map
-
 systemd_shutdown_SOURCES = \
 	src/mount-setup.c \
 	src/umount.c \
@@ -1598,6 +1592,16 @@ INSTALL_DATA_HOOKS += \
 
 EXTRA_DIST += \
 	units/systemd-localed.service.in
+
+dist_pkgdata_DATA = \
+	src/locale/kbd-model-map
+
+dist_noinst_SCRIPT = \
+	src/locale/generate-kbd-model-map
+
+update-kbd-model-map:
+	src/locale/generate-kbd-model-map > src/locale/kbd-model-map
+
 endif
 
 # ------------------------------------------------------------------------------
@@ -2340,6 +2344,3 @@ upload: all distcheck
 
 git-tag:
 	git tag "v$(VERSION)" -m "systemd $(VERSION)"
-
-update-kbd-model-map:
-	src/generate-kbd-model-map > src/kbd-model-map
diff --git a/src/generate-kbd-model-map b/src/generate-kbd-model-map
deleted file mode 100755
index 624c517..0000000
--- a/src/generate-kbd-model-map
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/python
-
-import sys
-import system_config_keyboard.keyboard_models
-
-def strdash(s):
-        return s.strip() or '-'
-
-def tab_extend(s, n=1):
-        s = strdash(s)
-        k = len(s) // 8
-
-        if k >= n:
-                f = 1
-        else:
-                f = n - k
-
-        return s + '\t'*f
-
-
-models = system_config_keyboard.keyboard_models.KeyboardModels().get_models()
-
-print "# Generated from system-config-keyboard's model list"
-print "# consolelayout\t\txlayout\txmodel\t\txvariant\txoptions"
-
-for key, value in reversed(models.items()):
-        options = "terminate:ctrl_alt_bksp"
-        if value[4]:
-                options += ',' + value[4]
-
-        print ''.join((tab_extend(key, 3), tab_extend(value[1]),
-                       tab_extend(value[2], 2), tab_extend(value[3], 2),
-                       options))
diff --git a/src/kbd-model-map b/src/kbd-model-map
deleted file mode 100644
index a895880..0000000
--- a/src/kbd-model-map
+++ /dev/null
@@ -1,72 +0,0 @@
-# Generated from system-config-keyboard's model list
-# consolelayout		xlayout	xmodel		xvariant	xoptions
-sg			ch	pc105		de_nodeadkeys	terminate:ctrl_alt_bksp
-nl			nl	pc105		-		terminate:ctrl_alt_bksp
-mk-utf			mkd,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-trq			tr	pc105		-		terminate:ctrl_alt_bksp
-guj			in,us	pc105		guj		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-uk			gb	pc105		-		terminate:ctrl_alt_bksp
-is-latin1		is	pc105		-		terminate:ctrl_alt_bksp
-de			de	pc105		-		terminate:ctrl_alt_bksp
-gur			gur,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-la-latin1		latam	pc105		-		terminate:ctrl_alt_bksp
-us			us	pc105+inet	-		terminate:ctrl_alt_bksp
-ko			kr	pc105		-		terminate:ctrl_alt_bksp
-ro-std			ro	pc105		std		terminate:ctrl_alt_bksp
-de-latin1		de	pc105		-		terminate:ctrl_alt_bksp
-tml-inscript		in,us	pc105		tam		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-slovene			si	pc105		-		terminate:ctrl_alt_bksp
-hu101			hu	pc105		qwerty		terminate:ctrl_alt_bksp
-jp106			jp	jp106		-		terminate:ctrl_alt_bksp
-croat			hr	pc105		-		terminate:ctrl_alt_bksp
-ben-probhat		in,us	pc105		ben_probhat	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-fi-latin1		fi	pc105		-		terminate:ctrl_alt_bksp
-it2			it	pc105		-		terminate:ctrl_alt_bksp
-hu			hu	pc105		-		terminate:ctrl_alt_bksp
-sr-latin		rs	pc105		latin		terminate:ctrl_alt_bksp
-fi			fi	pc105		-		terminate:ctrl_alt_bksp
-fr_CH			ch	pc105		fr		terminate:ctrl_alt_bksp
-dk-latin1		dk	pc105		-		terminate:ctrl_alt_bksp
-fr			fr	pc105		-		terminate:ctrl_alt_bksp
-it			it	pc105		-		terminate:ctrl_alt_bksp
-tml-uni			in,us	pc105		tam_TAB		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-ua-utf			ua,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-fr-latin1		fr	pc105		-		terminate:ctrl_alt_bksp
-sg-latin1		ch	pc105		de_nodeadkeys	terminate:ctrl_alt_bksp
-be-latin1		be	pc105		-		terminate:ctrl_alt_bksp
-dk			dk	pc105		-		terminate:ctrl_alt_bksp
-fr-pc			fr	pc105		-		terminate:ctrl_alt_bksp
-bg_pho-utf8		bg,us	pc105		,phonetic	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-it-ibm			it	pc105		-		terminate:ctrl_alt_bksp
-cz-us-qwertz		cz,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-ar-digits		ara,us	pc105		digits		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-br-abnt2		br	abnt2		-		terminate:ctrl_alt_bksp
-ro			ro	pc105		-		terminate:ctrl_alt_bksp
-us-acentos		us	pc105		intl		terminate:ctrl_alt_bksp
-pt-latin1		pt	pc105		-		terminate:ctrl_alt_bksp
-ro-std-cedilla		ro	pc105		std_cedilla	terminate:ctrl_alt_bksp
-tj			tj	pc105		-		terminate:ctrl_alt_bksp
-ar-qwerty		ara,us	pc105		qwerty		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-ar-azerty-digits	ara,us	pc105		azerty_digits	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-ben			in,us	pc105		ben		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-de-latin1-nodeadkeys	de	pc105		nodeadkeys	terminate:ctrl_alt_bksp
-no			no	pc105		-		terminate:ctrl_alt_bksp
-bg_bds-utf8		bg,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-dvorak			us	pc105		dvorak		terminate:ctrl_alt_bksp
-ru			ru,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-cz-lat2			cz	pc105		qwerty		terminate:ctrl_alt_bksp
-pl2			pl	pc105		-		terminate:ctrl_alt_bksp
-es			es	pc105		-		terminate:ctrl_alt_bksp
-ro-cedilla		ro	pc105		cedilla		terminate:ctrl_alt_bksp
-ie			ie	pc105		-		terminate:ctrl_alt_bksp
-ar-azerty		ara,us	pc105		azerty		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-ar-qwerty-digits	ara,us	pc105		qwerty_digits	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-et			ee	pc105		-		terminate:ctrl_alt_bksp
-sk-qwerty		sk	pc105		-		terminate:ctrl_alt_bksp,qwerty
-dev			dev,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
-fr-latin9		fr	pc105		latin9		terminate:ctrl_alt_bksp
-fr_CH-latin1		ch	pc105		fr		terminate:ctrl_alt_bksp
-cf			ca(fr)	pc105		-		terminate:ctrl_alt_bksp
-sv-latin1		se	pc105		-		terminate:ctrl_alt_bksp
-sr-cy			rs	pc105		-		terminate:ctrl_alt_bksp
-gr			gr,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
diff --git a/src/locale/generate-kbd-model-map b/src/locale/generate-kbd-model-map
new file mode 100755
index 0000000..624c517
--- /dev/null
+++ b/src/locale/generate-kbd-model-map
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+import sys
+import system_config_keyboard.keyboard_models
+
+def strdash(s):
+        return s.strip() or '-'
+
+def tab_extend(s, n=1):
+        s = strdash(s)
+        k = len(s) // 8
+
+        if k >= n:
+                f = 1
+        else:
+                f = n - k
+
+        return s + '\t'*f
+
+
+models = system_config_keyboard.keyboard_models.KeyboardModels().get_models()
+
+print "# Generated from system-config-keyboard's model list"
+print "# consolelayout\t\txlayout\txmodel\t\txvariant\txoptions"
+
+for key, value in reversed(models.items()):
+        options = "terminate:ctrl_alt_bksp"
+        if value[4]:
+                options += ',' + value[4]
+
+        print ''.join((tab_extend(key, 3), tab_extend(value[1]),
+                       tab_extend(value[2], 2), tab_extend(value[3], 2),
+                       options))
diff --git a/src/locale/kbd-model-map b/src/locale/kbd-model-map
new file mode 100644
index 0000000..a895880
--- /dev/null
+++ b/src/locale/kbd-model-map
@@ -0,0 +1,72 @@
+# Generated from system-config-keyboard's model list
+# consolelayout		xlayout	xmodel		xvariant	xoptions
+sg			ch	pc105		de_nodeadkeys	terminate:ctrl_alt_bksp
+nl			nl	pc105		-		terminate:ctrl_alt_bksp
+mk-utf			mkd,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+trq			tr	pc105		-		terminate:ctrl_alt_bksp
+guj			in,us	pc105		guj		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+uk			gb	pc105		-		terminate:ctrl_alt_bksp
+is-latin1		is	pc105		-		terminate:ctrl_alt_bksp
+de			de	pc105		-		terminate:ctrl_alt_bksp
+gur			gur,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+la-latin1		latam	pc105		-		terminate:ctrl_alt_bksp
+us			us	pc105+inet	-		terminate:ctrl_alt_bksp
+ko			kr	pc105		-		terminate:ctrl_alt_bksp
+ro-std			ro	pc105		std		terminate:ctrl_alt_bksp
+de-latin1		de	pc105		-		terminate:ctrl_alt_bksp
+tml-inscript		in,us	pc105		tam		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+slovene			si	pc105		-		terminate:ctrl_alt_bksp
+hu101			hu	pc105		qwerty		terminate:ctrl_alt_bksp
+jp106			jp	jp106		-		terminate:ctrl_alt_bksp
+croat			hr	pc105		-		terminate:ctrl_alt_bksp
+ben-probhat		in,us	pc105		ben_probhat	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fi-latin1		fi	pc105		-		terminate:ctrl_alt_bksp
+it2			it	pc105		-		terminate:ctrl_alt_bksp
+hu			hu	pc105		-		terminate:ctrl_alt_bksp
+sr-latin		rs	pc105		latin		terminate:ctrl_alt_bksp
+fi			fi	pc105		-		terminate:ctrl_alt_bksp
+fr_CH			ch	pc105		fr		terminate:ctrl_alt_bksp
+dk-latin1		dk	pc105		-		terminate:ctrl_alt_bksp
+fr			fr	pc105		-		terminate:ctrl_alt_bksp
+it			it	pc105		-		terminate:ctrl_alt_bksp
+tml-uni			in,us	pc105		tam_TAB		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ua-utf			ua,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin1		fr	pc105		-		terminate:ctrl_alt_bksp
+sg-latin1		ch	pc105		de_nodeadkeys	terminate:ctrl_alt_bksp
+be-latin1		be	pc105		-		terminate:ctrl_alt_bksp
+dk			dk	pc105		-		terminate:ctrl_alt_bksp
+fr-pc			fr	pc105		-		terminate:ctrl_alt_bksp
+bg_pho-utf8		bg,us	pc105		,phonetic	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+it-ibm			it	pc105		-		terminate:ctrl_alt_bksp
+cz-us-qwertz		cz,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-digits		ara,us	pc105		digits		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+br-abnt2		br	abnt2		-		terminate:ctrl_alt_bksp
+ro			ro	pc105		-		terminate:ctrl_alt_bksp
+us-acentos		us	pc105		intl		terminate:ctrl_alt_bksp
+pt-latin1		pt	pc105		-		terminate:ctrl_alt_bksp
+ro-std-cedilla		ro	pc105		std_cedilla	terminate:ctrl_alt_bksp
+tj			tj	pc105		-		terminate:ctrl_alt_bksp
+ar-qwerty		ara,us	pc105		qwerty		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-azerty-digits	ara,us	pc105		azerty_digits	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ben			in,us	pc105		ben		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+de-latin1-nodeadkeys	de	pc105		nodeadkeys	terminate:ctrl_alt_bksp
+no			no	pc105		-		terminate:ctrl_alt_bksp
+bg_bds-utf8		bg,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+dvorak			us	pc105		dvorak		terminate:ctrl_alt_bksp
+ru			ru,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+cz-lat2			cz	pc105		qwerty		terminate:ctrl_alt_bksp
+pl2			pl	pc105		-		terminate:ctrl_alt_bksp
+es			es	pc105		-		terminate:ctrl_alt_bksp
+ro-cedilla		ro	pc105		cedilla		terminate:ctrl_alt_bksp
+ie			ie	pc105		-		terminate:ctrl_alt_bksp
+ar-azerty		ara,us	pc105		azerty		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-qwerty-digits	ara,us	pc105		qwerty_digits	terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+et			ee	pc105		-		terminate:ctrl_alt_bksp
+sk-qwerty		sk	pc105		-		terminate:ctrl_alt_bksp,qwerty
+dev			dev,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin9		fr	pc105		latin9		terminate:ctrl_alt_bksp
+fr_CH-latin1		ch	pc105		fr		terminate:ctrl_alt_bksp
+cf			ca(fr)	pc105		-		terminate:ctrl_alt_bksp
+sv-latin1		se	pc105		-		terminate:ctrl_alt_bksp
+sr-cy			rs	pc105		-		terminate:ctrl_alt_bksp
+gr			gr,us	pc105		-		terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
diff --git a/src/localed.c b/src/localed.c
deleted file mode 100644
index e69de29..0000000

commit b4d0195b0598df76d30f006507fa8466f5a5d330
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Dec 31 19:59:09 2011 +0100

    cryptsetup: split off cryptsetup into its own subdir

diff --git a/Makefile.am b/Makefile.am
index 4c2d165..0c3e970 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -199,14 +199,6 @@ rootlibexec_PROGRAMS = \
 systemgenerator_PROGRAMS = \
 	systemd-getty-generator
 
-if HAVE_LIBCRYPTSETUP
-rootlibexec_PROGRAMS += \
-	systemd-cryptsetup
-
-systemgenerator_PROGRAMS += \
-	systemd-cryptsetup-generator
-endif
-
 noinst_PROGRAMS = \
 	test-engine \
 	test-job-type \
@@ -278,7 +270,6 @@ dist_systemunit_DATA = \
 	units/local-fs-pre.target \
 	units/remote-fs.target \
 	units/remote-fs-pre.target \
-	units/cryptsetup.target \
 	units/network.target \
 	units/nss-lookup.target \
 	units/mail-transfer-agent.target \
@@ -579,7 +570,7 @@ libsystemd_core_la_LIBADD = \
 	$(CAP_LIBS)
 
 # This is needed because automake is buggy in how it generates the
-# rules for C programs, but not Vala programs.  We therefore can't
+# rules for C programs, but not Vala programs.	We therefore can't
 # list the .h files as dependencies if we want make dist to work.
 
 EXTRA_DIST += \
@@ -906,27 +897,6 @@ systemd_detect_virt_SOURCES = \
 systemd_detect_virt_LDADD = \
 	libsystemd-basic.la
 
-systemd_cryptsetup_SOURCES = \
-	src/cryptsetup.c \
-	src/ask-password-api.c
-
-systemd_cryptsetup_CFLAGS = \
-	$(AM_CFLAGS) \
-	$(LIBCRYPTSETUP_CFLAGS) \
-	$(UDEV_CFLAGS)
-
-systemd_cryptsetup_LDADD = \
-	$(LIBCRYPTSETUP_LIBS) \
-	$(UDEV_LIBS) \
-	libsystemd-basic.la
-
-systemd_cryptsetup_generator_SOURCES = \
-	src/cryptsetup-generator.c \
-	src/unit-name.c
-
-systemd_cryptsetup_generator_LDADD = \
-	libsystemd-basic.la
-
 systemd_getty_generator_SOURCES = \
 	src/getty-generator.c \
 	src/unit-name.c
@@ -1488,6 +1458,47 @@ MANPAGES += \
 endif
 
 # ------------------------------------------------------------------------------
+if HAVE_LIBCRYPTSETUP
+rootlibexec_PROGRAMS += \
+	systemd-cryptsetup
+
+systemgenerator_PROGRAMS += \
+	systemd-cryptsetup-generator
+
+dist_systemunit_DATA += \
+	units/cryptsetup.target
+
+systemd_cryptsetup_SOURCES = \
+	src/cryptsetup/cryptsetup.c \
+	src/ask-password-api.c
+
+systemd_cryptsetup_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(LIBCRYPTSETUP_CFLAGS) \
+	$(UDEV_CFLAGS)
+
+systemd_cryptsetup_LDADD = \
+	$(LIBCRYPTSETUP_LIBS) \
+	$(UDEV_LIBS) \
+	libsystemd-basic.la
+
+systemd_cryptsetup_generator_SOURCES = \
+	src/cryptsetup/cryptsetup-generator.c \
+	src/unit-name.c
+
+systemd_cryptsetup_generator_LDADD = \
+	libsystemd-basic.la
+
+cryptsetup-install-data-hook:
+	( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \
+		rm -f cryptsetup.target && \
+		$(LN_S) ../cryptsetup.target cryptsetup.target )
+
+INSTALL_DATA_HOOKS += \
+	cryptsetup-install-data-hook
+endif
+
+# ------------------------------------------------------------------------------
 if ENABLE_HOSTNAMED
 systemd_hostnamed_SOURCES = \
 	src/hostname/hostnamed.c \
@@ -1908,7 +1919,7 @@ endif
 
 SED_PROCESS = \
 	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
-	$(SED)  -e 's, at rootlibexecdir\@,$(rootlibexecdir),g' \
+	$(SED)	-e 's, at rootlibexecdir\@,$(rootlibexecdir),g' \
 		-e 's, at rootbindir\@,$(rootbindir),g' \
 		-e 's, at bindir\@,$(bindir),g' \
 		-e 's, at SYSTEMCTL\@,$(rootbindir)/systemctl,g' \
@@ -2180,8 +2191,7 @@ systemd-install-data-hook:
 			systemd-tmpfiles-setup.service \
 			systemd-sysctl.service \
 			systemd-ask-password-console.path \
-			systemd-kmsg-syslogd.service \
-			cryptsetup.target && \
+			systemd-kmsg-syslogd.service && \
 		$(LN_S) ../dev-hugepages.mount dev-hugepages.mount && \
 		$(LN_S) ../dev-mqueue.mount dev-mqueue.mount && \
 		$(LN_S) ../sys-kernel-config.mount sys-kernel-config.mount && \
@@ -2193,8 +2203,7 @@ systemd-install-data-hook:
 		$(LN_S) ../systemd-tmpfiles-setup.service systemd-tmpfiles-setup.service && \
 		$(LN_S) ../systemd-sysctl.service systemd-sysctl.service && \
 		$(LN_S) ../systemd-ask-password-console.path systemd-ask-password-console.path && \
-		$(LN_S) ../systemd-kmsg-syslogd.service && \
-		$(LN_S) ../cryptsetup.target cryptsetup.target )
+		$(LN_S) ../systemd-kmsg-syslogd.service )
 	( cd $(DESTDIR)$(systemunitdir)/basic.target.wants && \
 		rm -f systemd-tmpfiles-clean.timer && \
 		$(LN_S) ../systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.timer )
diff --git a/src/cryptsetup-generator.c b/src/cryptsetup-generator.c
deleted file mode 100644
index a48b7a4..0000000
--- a/src/cryptsetup-generator.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "log.h"
-#include "util.h"
-#include "unit-name.h"
-
-const char *arg_dest = "/tmp";
-
-static bool has_option(const char *haystack, const char *needle) {
-        const char *f = haystack;
-        size_t l;
-
-        assert(needle);
-
-        if (!haystack)
-                return false;
-
-        l = strlen(needle);
-
-        while ((f = strstr(f, needle))) {
-
-                if (f > haystack && f[-1] != ',') {
-                        f++;
-                        continue;
-                }
-
-                if (f[l] != 0 && f[l] != ',') {
-                        f++;
-                        continue;
-                }
-
-                return true;
-        }
-
-        return false;
-}
-
-static int create_disk(
-                const char *name,
-                const char *device,
-                const char *password,
-                const char *options) {
-
-        char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
-        int r;
-        FILE *f = NULL;
-        bool noauto, nofail;
-
-        assert(name);
-        assert(device);
-
-        noauto = has_option(options, "noauto");
-        nofail = has_option(options, "nofail");
-
-        if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) {
-                r = -ENOMEM;
-                log_error("Failed to allocate unit name.");
-                goto fail;
-        }
-
-        if (asprintf(&p, "%s/%s", arg_dest, n) < 0) {
-                r = -ENOMEM;
-                log_error("Failed to allocate unit file name.");
-                goto fail;
-        }
-
-        if (!(u = fstab_node_to_udev_node(device))) {
-                r = -ENOMEM;
-                log_error("Failed to allocate device node.");
-                goto fail;
-        }
-
-        if (!(d = unit_name_from_path(u, ".device"))) {
-                r = -ENOMEM;
-                log_error("Failed to allocate device name.");
-                goto fail;
-        }
-
-        if (!(f = fopen(p, "wxe"))) {
-                r = -errno;
-                log_error("Failed to create unit file: %m");
-                goto fail;
-        }
-
-        fprintf(f,
-                "[Unit]\n"
-                "Description=Cryptography Setup for %%I\n"
-                "Conflicts=umount.target\n"
-                "DefaultDependencies=no\n"
-                "BindTo=%s dev-mapper-%%i.device\n"
-                "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
-                "Before=umount.target\n",
-                d, d);
-
-        if (!nofail)
-                fprintf(f,
-                        "Before=cryptsetup.target\n");
-
-        if (password && (streq(password, "/dev/urandom") ||
-                         streq(password, "/dev/random") ||
-                         streq(password, "/dev/hw_random")))
-                fprintf(f,
-                        "After=systemd-random-seed-load.service\n");
-        else
-                fprintf(f,
-                        "Before=local-fs.target\n");
-
-        fprintf(f,
-                "\n[Service]\n"
-                "Type=oneshot\n"
-                "RemainAfterExit=yes\n"
-                "TimeoutSec=0\n" /* the binary handles timeouts anyway */
-                "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
-                "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
-                name, u, strempty(password), strempty(options),
-                name);
-
-        if (has_option(options, "tmp"))
-                fprintf(f,
-                        "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
-                        name);
-
-        if (has_option(options, "swap"))
-                fprintf(f,
-                        "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
-                        name);
-
-        fflush(f);
-
-        if (ferror(f)) {
-                r = -errno;
-                log_error("Failed to write file: %m");
-                goto fail;
-        }
-
-        if (asprintf(&from, "../%s", n) < 0) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        if (!noauto) {
-
-                if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                mkdir_parents(to, 0755);
-
-                if (symlink(from, to) < 0) {
-                        log_error("Failed to create symlink '%s' to '%s': %m", from, to);
-                        r = -errno;
-                        goto fail;
-                }
-
-                free(to);
-                to = NULL;
-
-                if (!nofail)
-                        asprintf(&to, "%s/cryptsetup.target.requires/%s", arg_dest, n);
-                else
-                        asprintf(&to, "%s/cryptsetup.target.wants/%s", arg_dest, n);
-
-                if (!to) {
-                        r = -ENOMEM;
-                        goto fail;
-                }
-
-                mkdir_parents(to, 0755);
-
-                if (symlink(from, to) < 0) {
-                        log_error("Failed to create symlink '%s' to '%s': %m", from, to);
-                        r = -errno;
-                        goto fail;
-                }
-        }
-
-        free(to);
-        to = NULL;
-
-        e = unit_name_escape(name);
-        if (asprintf(&to, "%s/dev-mapper-%s.device.requires/%s", arg_dest, e, n) < 0) {
-                r = -ENOMEM;
-                goto fail;
-        }
-
-        mkdir_parents(to, 0755);
-
-        if (symlink(from, to) < 0) {
-                log_error("Failed to create symlink '%s' to '%s': %m", from, to);
-                r = -errno;
-                goto fail;
-        }
-
-        r = 0;
-
-fail:
-        free(p);
-        free(n);
-        free(d);
-        free(e);
-
-        free(from);
-        free(to);
-
-        if (f)
-                fclose(f);
-
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        FILE *f;
-        int r = EXIT_SUCCESS;
-        unsigned n = 0;
-
-        if (argc > 2) {
-                log_error("This program takes one or no arguments.");
-                return EXIT_FAILURE;
-        }
-
-        if (argc > 1)
-                arg_dest = argv[1];
-
-        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        if (!(f = fopen("/etc/crypttab", "re"))) {
-
-                if (errno == ENOENT)
-                        r = EXIT_SUCCESS;
-                else {
-                        r = EXIT_FAILURE;
-                        log_error("Failed to open /etc/crypttab: %m");
-                }
-
-                goto finish;
-        }
-
-        for (;;) {
-                char line[LINE_MAX], *l;
-                char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
-                int k;
-
-                if (!(fgets(line, sizeof(line), f)))
-                        break;
-
-                n++;
-
-                l = strstrip(line);
-                if (*l == '#' || *l == 0)
-                        continue;
-
-                if ((k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options)) < 2 || k > 4) {
-                        log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
-                        r = EXIT_FAILURE;
-                        goto next;
-                }
-
-                if (create_disk(name, device, password, options) < 0)
-                        r = EXIT_FAILURE;
-
-        next:
-                free(name);
-                free(device);
-                free(password);
-                free(options);
-        }
-
-finish:
-        return r;
-}
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
deleted file mode 100644
index ac7b6d6..0000000
--- a/src/cryptsetup.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <mntent.h>
-
-#include <libcryptsetup.h>
-#include <libudev.h>
-
-#include "log.h"
-#include "util.h"
-#include "strv.h"
-#include "ask-password-api.h"
-#include "def.h"
-
-static const char *opt_type = NULL; /* LUKS1 or PLAIN */
-static char *opt_cipher = NULL;
-static unsigned opt_key_size = 0;
-static char *opt_hash = NULL;
-static unsigned opt_tries = 0;
-static bool opt_readonly = false;
-static bool opt_verify = false;
-static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC;
-
-/* Options Debian's crypttab knows we don't:
-
-    offset=
-    skip=
-    precheck=
-    check=
-    checkargs=
-    noearly=
-    loud=
-    keyscript=
-*/
-
-static int parse_one_option(const char *option) {
-        assert(option);
-
-        /* Handled outside of this tool */
-        if (streq(option, "noauto"))
-                return 0;
-
-        if (startswith(option, "cipher=")) {
-                char *t;
-
-                if (!(t = strdup(option+7)))
-                        return -ENOMEM;
-
-                free(opt_cipher);
-                opt_cipher = t;
-
-        } else if (startswith(option, "size=")) {
-
-                if (safe_atou(option+5, &opt_key_size) < 0) {
-                        log_error("size= parse failure, ignoring.");
-                        return 0;
-                }
-
-        } else if (startswith(option, "hash=")) {
-                char *t;
-
-                if (!(t = strdup(option+5)))
-                        return -ENOMEM;
-
-                free(opt_hash);
-                opt_hash = t;
-
-        } else if (startswith(option, "tries=")) {
-
-                if (safe_atou(option+6, &opt_tries) < 0) {
-                        log_error("tries= parse failure, ignoring.");
-                        return 0;
-                }
-
-        } else if (streq(option, "readonly"))
-                opt_readonly = true;
-        else if (streq(option, "verify"))
-                opt_verify = true;
-        else if (streq(option, "luks"))
-                opt_type = CRYPT_LUKS1;
-        else if (streq(option, "plain") ||
-                 streq(option, "swap") ||
-                 streq(option, "tmp"))
-                opt_type = CRYPT_PLAIN;
-        else if (startswith(option, "timeout=")) {
-
-                if (parse_usec(option+8, &opt_timeout) < 0) {
-                        log_error("timeout= parse failure, ignoring.");
-                        return 0;
-                }
-
-        } else if (!streq(option, "none"))
-                log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
-
-        return 0;
-}
-
-static int parse_options(const char *options) {
-        char *state;
-        char *w;
-        size_t l;
-
-        assert(options);
-
-        FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
-                char *o;
-                int r;
-
-                if (!(o = strndup(w, l)))
-                        return -ENOMEM;
-
-                r = parse_one_option(o);
-                free(o);
-
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static void log_glue(int level, const char *msg, void *usrptr) {
-        log_debug("%s", msg);
-}
-
-static char *disk_description(const char *path) {
-        struct udev *udev = NULL;
-        struct udev_device *device = NULL;
-        struct stat st;
-        char *description = NULL;
-        const char *model;
-
-        assert(path);
-
-        if (stat(path, &st) < 0)
-                return NULL;
-
-        if (!S_ISBLK(st.st_mode))
-                return NULL;
-
-        if (!(udev = udev_new()))
-                return NULL;
-
-        if (!(device = udev_device_new_from_devnum(udev, 'b', st.st_rdev)))
-                goto finish;
-
-        if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) ||
-            (model = udev_device_get_property_value(device, "ID_MODEL")) ||
-            (model = udev_device_get_property_value(device, "DM_NAME")))
-                description = strdup(model);
-
-finish:
-        if (device)
-                udev_device_unref(device);
-
-        if (udev)
-                udev_unref(udev);
-
-        return description;
-}
-
-static char *disk_mount_point(const char *label) {
-        char *mp = NULL, *device = NULL;
-        FILE *f = NULL;
-        struct mntent *m;
-
-        /* Yeah, we don't support native systemd unit files here for now */
-
-        if (asprintf(&device, "/dev/mapper/%s", label) < 0)
-                goto finish;
-
-        if (!(f = setmntent("/etc/fstab", "r")))
-                goto finish;
-
-        while ((m = getmntent(f)))
-                if (path_equal(m->mnt_fsname, device)) {
-                        mp = strdup(m->mnt_dir);
-                        break;
-                }
-
-finish:
-        if (f)
-                endmntent(f);
-
-        free(device);
-
-        return mp;
-}
-
-static int help(void) {
-
-        printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
-               "%s detach VOLUME\n\n"
-               "Attaches or detaches an encrypted block device.\n",
-               program_invocation_short_name,
-               program_invocation_short_name);
-
-        return 0;
-}
-
-int main(int argc, char *argv[]) {
-        int r = EXIT_FAILURE;
-        struct crypt_device *cd = NULL;
-        char **passwords = NULL, *truncated_cipher = NULL;
-        const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
-        char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
-        unsigned keyfile_size = 0;
-
-        if (argc <= 1) {
-                help();
-                return EXIT_SUCCESS;
-        }
-
-        if (argc < 3) {
-                log_error("This program requires at least two arguments.");
-                return EXIT_FAILURE;
-        }
-
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        if (streq(argv[1], "attach")) {
-                uint32_t flags = 0;
-                int k;
-                unsigned try;
-                const char *key_file = NULL;
-                usec_t until;
-                crypt_status_info status;
-
-                /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
-
-                if (argc < 4) {
-                        log_error("attach requires at least two arguments.");
-                        goto finish;
-                }
-
-                if (argc >= 5 &&
-                    argv[4][0] &&
-                    !streq(argv[4], "-") &&
-                    !streq(argv[4], "none")) {
-
-                        if (!path_is_absolute(argv[4]))
-                                log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
-                        else
-                                key_file = argv[4];
-                }
-
-                if (argc >= 6 && argv[5][0] && !streq(argv[5], "-"))
-                        parse_options(argv[5]);
-
-                /* A delicious drop of snake oil */
-                mlockall(MCL_FUTURE);
-
-                description = disk_description(argv[3]);
-                mount_point = disk_mount_point(argv[2]);
-
-                if (description && streq(argv[2], description)) {
-                        /* If the description string is simply the
-                         * volume name, then let's not show this
-                         * twice */
-                        free(description);
-                        description = NULL;
-                }
-
-                if (mount_point && description)
-                        asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
-                else if (mount_point)
-                        asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
-                else if (description)
-                        asprintf(&name_buffer, "%s (%s)", description, argv[2]);
-
-                name = name_buffer ? name_buffer : argv[2];
-
-                if ((k = crypt_init(&cd, argv[3]))) {
-                        log_error("crypt_init() failed: %s", strerror(-k));
-                        goto finish;
-                }
-
-                crypt_set_log_callback(cd, log_glue, NULL);
-
-                status = crypt_status(cd, argv[2]);
-                if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
-                        log_info("Volume %s already active.", argv[2]);
-                        r = EXIT_SUCCESS;
-                        goto finish;
-                }
-
-                if (opt_readonly)
-                        flags |= CRYPT_ACTIVATE_READONLY;
-
-                if (opt_timeout > 0)
-                        until = now(CLOCK_MONOTONIC) + opt_timeout;
-                else
-                        until = 0;
-
-                opt_tries = opt_tries > 0 ? opt_tries : 3;
-                opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
-                hash = opt_hash ? opt_hash : "ripemd160";
-
-                if (opt_cipher) {
-                        size_t l;
-
-                        l = strcspn(opt_cipher, "-");
-
-                        if (!(truncated_cipher = strndup(opt_cipher, l))) {
-                                log_error("Out of memory");
-                                goto finish;
-                        }
-
-                        cipher = truncated_cipher;
-                        cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
-                } else {
-                        cipher = "aes";
-                        cipher_mode = "cbc-essiv:sha256";
-                }
-
-                for (try = 0; try < opt_tries; try++) {
-                        bool pass_volume_key = false;
-
-                        strv_free(passwords);
-                        passwords = NULL;
-
-                        if (!key_file) {
-                                char *text;
-                                char **p;
-
-                                if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
-                                        log_error("Out of memory");
-                                        goto finish;
-                                }
-
-                                k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
-                                free(text);
-
-                                if (k < 0) {
-                                        log_error("Failed to query password: %s", strerror(-k));
-                                        goto finish;
-                                }
-
-                                if (opt_verify) {
-                                        char **passwords2 = NULL;
-
-                                        assert(strv_length(passwords) == 1);
-
-                                        if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
-                                                log_error("Out of memory");
-                                                goto finish;
-                                        }
-
-                                        k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
-                                        free(text);
-
-                                        if (k < 0) {
-                                                log_error("Failed to query verification password: %s", strerror(-k));
-                                                goto finish;
-                                        }
-
-                                        assert(strv_length(passwords2) == 1);
-
-                                        if (!streq(passwords[0], passwords2[0])) {
-                                                log_warning("Passwords did not match, retrying.");
-                                                strv_free(passwords2);
-                                                continue;
-                                        }
-
-                                        strv_free(passwords2);
-                                }
-
-                                strv_uniq(passwords);
-
-                                STRV_FOREACH(p, passwords) {
-                                        char *c;
-
-                                        if (strlen(*p)+1 >= opt_key_size)
-                                                continue;
-
-                                        /* Pad password if necessary */
-                                        if (!(c = new(char, opt_key_size))) {
-                                                log_error("Out of memory.");
-                                                goto finish;
-                                        }
-
-                                        strncpy(c, *p, opt_key_size);
-                                        free(*p);
-                                        *p = c;
-                                }
-                        }
-
-                        k = 0;
-
-                        if (!opt_type || streq(opt_type, CRYPT_LUKS1))
-                                k = crypt_load(cd, CRYPT_LUKS1, NULL);
-
-                        if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
-                                struct crypt_params_plain params;
-
-                                zero(params);
-                                params.hash = hash;
-
-                                /* In contrast to what the name
-                                 * crypt_setup() might suggest this
-                                 * doesn't actually format anything,
-                                 * it just configures encryption
-                                 * parameters when used for plain
-                                 * mode. */
-                                k = crypt_format(cd, CRYPT_PLAIN,
-                                                 cipher,
-                                                 cipher_mode,
-                                                 NULL,
-                                                 NULL,
-                                                 opt_key_size / 8,
-                                                 &params);
-
-                                pass_volume_key = streq(hash, "plain");
-
-                               /* for CRYPT_PLAIN limit reads
-                                * from keyfile to key length */
-                                keyfile_size = opt_key_size / 8;
-                        }
-
-                        if (k < 0) {
-                                log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
-                                goto finish;
-                        }
-
-                        log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
-                                 crypt_get_cipher(cd),
-                                 crypt_get_cipher_mode(cd),
-                                 crypt_get_volume_key_size(cd)*8,
-                                 argv[3]);
-
-                        if (key_file)
-                                k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size, flags);
-                        else {
-                                char **p;
-
-                                STRV_FOREACH(p, passwords) {
-
-                                        if (pass_volume_key)
-                                                k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
-                                        else
-                                                k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
-
-                                        if (k >= 0)
-                                                break;
-                                }
-                        }
-
-                        if (k >= 0)
-                                break;
-
-                        if (k != -EPERM) {
-                                log_error("Failed to activate: %s", strerror(-k));
-                                goto finish;
-                        }
-
-                        log_warning("Invalid passphrase.");
-                }
-
-                if (try >= opt_tries) {
-                        log_error("Too many attempts.");
-                        r = EXIT_FAILURE;
-                        goto finish;
-                }
-
-        } else if (streq(argv[1], "detach")) {
-                int k;
-
-                if ((k = crypt_init_by_name(&cd, argv[2]))) {
-                        log_error("crypt_init() failed: %s", strerror(-k));
-                        goto finish;
-                }
-
-                crypt_set_log_callback(cd, log_glue, NULL);
-
-                if ((k = crypt_deactivate(cd, argv[2])) < 0) {
-                        log_error("Failed to deactivate: %s", strerror(-k));
-                        goto finish;
-                }
-
-        } else {
-                log_error("Unknown verb %s.", argv[1]);
-                goto finish;
-        }
-
-        r = EXIT_SUCCESS;
-
-finish:
-
-        if (cd)
-                crypt_free(cd);
-
-        free(opt_cipher);
-        free(opt_hash);
-
-        free(truncated_cipher);
-
-        strv_free(passwords);
-
-        free(description);
-        free(mount_point);
-        free(name_buffer);
-
-        return r;
-}
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
new file mode 100644
index 0000000..a48b7a4
--- /dev/null
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -0,0 +1,298 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "util.h"
+#include "unit-name.h"
+
+const char *arg_dest = "/tmp";
+
+static bool has_option(const char *haystack, const char *needle) {
+        const char *f = haystack;
+        size_t l;
+
+        assert(needle);
+
+        if (!haystack)
+                return false;
+
+        l = strlen(needle);
+
+        while ((f = strstr(f, needle))) {
+
+                if (f > haystack && f[-1] != ',') {
+                        f++;
+                        continue;
+                }
+
+                if (f[l] != 0 && f[l] != ',') {
+                        f++;
+                        continue;
+                }
+
+                return true;
+        }
+
+        return false;
+}
+
+static int create_disk(
+                const char *name,
+                const char *device,
+                const char *password,
+                const char *options) {
+
+        char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
+        int r;
+        FILE *f = NULL;
+        bool noauto, nofail;
+
+        assert(name);
+        assert(device);
+
+        noauto = has_option(options, "noauto");
+        nofail = has_option(options, "nofail");
+
+        if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) {
+                r = -ENOMEM;
+                log_error("Failed to allocate unit name.");
+                goto fail;
+        }
+
+        if (asprintf(&p, "%s/%s", arg_dest, n) < 0) {
+                r = -ENOMEM;
+                log_error("Failed to allocate unit file name.");
+                goto fail;
+        }
+
+        if (!(u = fstab_node_to_udev_node(device))) {
+                r = -ENOMEM;
+                log_error("Failed to allocate device node.");
+                goto fail;
+        }
+
+        if (!(d = unit_name_from_path(u, ".device"))) {
+                r = -ENOMEM;
+                log_error("Failed to allocate device name.");
+                goto fail;
+        }
+
+        if (!(f = fopen(p, "wxe"))) {
+                r = -errno;
+                log_error("Failed to create unit file: %m");
+                goto fail;
+        }
+
+        fprintf(f,
+                "[Unit]\n"
+                "Description=Cryptography Setup for %%I\n"
+                "Conflicts=umount.target\n"
+                "DefaultDependencies=no\n"
+                "BindTo=%s dev-mapper-%%i.device\n"
+                "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
+                "Before=umount.target\n",
+                d, d);
+
+        if (!nofail)
+                fprintf(f,
+                        "Before=cryptsetup.target\n");
+
+        if (password && (streq(password, "/dev/urandom") ||
+                         streq(password, "/dev/random") ||
+                         streq(password, "/dev/hw_random")))
+                fprintf(f,
+                        "After=systemd-random-seed-load.service\n");
+        else
+                fprintf(f,
+                        "Before=local-fs.target\n");
+
+        fprintf(f,
+                "\n[Service]\n"
+                "Type=oneshot\n"
+                "RemainAfterExit=yes\n"
+                "TimeoutSec=0\n" /* the binary handles timeouts anyway */
+                "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
+                "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
+                name, u, strempty(password), strempty(options),
+                name);
+
+        if (has_option(options, "tmp"))
+                fprintf(f,
+                        "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
+                        name);
+
+        if (has_option(options, "swap"))
+                fprintf(f,
+                        "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
+                        name);
+
+        fflush(f);
+
+        if (ferror(f)) {
+                r = -errno;
+                log_error("Failed to write file: %m");
+                goto fail;
+        }
+
+        if (asprintf(&from, "../%s", n) < 0) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        if (!noauto) {
+
+                if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                mkdir_parents(to, 0755);
+
+                if (symlink(from, to) < 0) {
+                        log_error("Failed to create symlink '%s' to '%s': %m", from, to);
+                        r = -errno;
+                        goto fail;
+                }
+
+                free(to);
+                to = NULL;
+
+                if (!nofail)
+                        asprintf(&to, "%s/cryptsetup.target.requires/%s", arg_dest, n);
+                else
+                        asprintf(&to, "%s/cryptsetup.target.wants/%s", arg_dest, n);
+
+                if (!to) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
+
+                mkdir_parents(to, 0755);
+
+                if (symlink(from, to) < 0) {
+                        log_error("Failed to create symlink '%s' to '%s': %m", from, to);
+                        r = -errno;
+                        goto fail;
+                }
+        }
+
+        free(to);
+        to = NULL;
+
+        e = unit_name_escape(name);
+        if (asprintf(&to, "%s/dev-mapper-%s.device.requires/%s", arg_dest, e, n) < 0) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        mkdir_parents(to, 0755);
+
+        if (symlink(from, to) < 0) {
+                log_error("Failed to create symlink '%s' to '%s': %m", from, to);
+                r = -errno;
+                goto fail;
+        }
+
+        r = 0;
+
+fail:
+        free(p);
+        free(n);
+        free(d);
+        free(e);
+
+        free(from);
+        free(to);
+
+        if (f)
+                fclose(f);
+
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        FILE *f;
+        int r = EXIT_SUCCESS;
+        unsigned n = 0;
+
+        if (argc > 2) {
+                log_error("This program takes one or no arguments.");
+                return EXIT_FAILURE;
+        }
+
+        if (argc > 1)
+                arg_dest = argv[1];
+
+        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        if (!(f = fopen("/etc/crypttab", "re"))) {
+
+                if (errno == ENOENT)
+                        r = EXIT_SUCCESS;
+                else {
+                        r = EXIT_FAILURE;
+                        log_error("Failed to open /etc/crypttab: %m");
+                }
+
+                goto finish;
+        }
+
+        for (;;) {
+                char line[LINE_MAX], *l;
+                char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
+                int k;
+
+                if (!(fgets(line, sizeof(line), f)))
+                        break;
+
+                n++;
+
+                l = strstrip(line);
+                if (*l == '#' || *l == 0)
+                        continue;
+
+                if ((k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options)) < 2 || k > 4) {
+                        log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
+                        r = EXIT_FAILURE;
+                        goto next;
+                }
+
+                if (create_disk(name, device, password, options) < 0)
+                        r = EXIT_FAILURE;
+
+        next:
+                free(name);
+                free(device);
+                free(password);
+                free(options);
+        }
+
+finish:
+        return r;
+}
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
new file mode 100644
index 0000000..ac7b6d6
--- /dev/null
+++ b/src/cryptsetup/cryptsetup.c
@@ -0,0 +1,529 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <mntent.h>
+
+#include <libcryptsetup.h>
+#include <libudev.h>
+
+#include "log.h"
+#include "util.h"
+#include "strv.h"
+#include "ask-password-api.h"
+#include "def.h"
+
+static const char *opt_type = NULL; /* LUKS1 or PLAIN */
+static char *opt_cipher = NULL;
+static unsigned opt_key_size = 0;
+static char *opt_hash = NULL;
+static unsigned opt_tries = 0;
+static bool opt_readonly = false;
+static bool opt_verify = false;
+static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC;
+
+/* Options Debian's crypttab knows we don't:
+
+    offset=
+    skip=
+    precheck=
+    check=
+    checkargs=
+    noearly=
+    loud=
+    keyscript=
+*/
+
+static int parse_one_option(const char *option) {
+        assert(option);
+
+        /* Handled outside of this tool */
+        if (streq(option, "noauto"))
+                return 0;
+
+        if (startswith(option, "cipher=")) {
+                char *t;
+
+                if (!(t = strdup(option+7)))
+                        return -ENOMEM;
+
+                free(opt_cipher);
+                opt_cipher = t;
+
+        } else if (startswith(option, "size=")) {
+
+                if (safe_atou(option+5, &opt_key_size) < 0) {
+                        log_error("size= parse failure, ignoring.");
+                        return 0;
+                }
+
+        } else if (startswith(option, "hash=")) {
+                char *t;
+
+                if (!(t = strdup(option+5)))
+                        return -ENOMEM;
+
+                free(opt_hash);
+                opt_hash = t;
+
+        } else if (startswith(option, "tries=")) {
+
+                if (safe_atou(option+6, &opt_tries) < 0) {
+                        log_error("tries= parse failure, ignoring.");
+                        return 0;
+                }
+
+        } else if (streq(option, "readonly"))
+                opt_readonly = true;
+        else if (streq(option, "verify"))
+                opt_verify = true;
+        else if (streq(option, "luks"))
+                opt_type = CRYPT_LUKS1;
+        else if (streq(option, "plain") ||
+                 streq(option, "swap") ||
+                 streq(option, "tmp"))
+                opt_type = CRYPT_PLAIN;
+        else if (startswith(option, "timeout=")) {
+
+                if (parse_usec(option+8, &opt_timeout) < 0) {
+                        log_error("timeout= parse failure, ignoring.");
+                        return 0;
+                }
+
+        } else if (!streq(option, "none"))
+                log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
+
+        return 0;
+}
+
+static int parse_options(const char *options) {
+        char *state;
+        char *w;
+        size_t l;
+
+        assert(options);
+
+        FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
+                char *o;
+                int r;
+
+                if (!(o = strndup(w, l)))
+                        return -ENOMEM;
+
+                r = parse_one_option(o);
+                free(o);
+
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+static void log_glue(int level, const char *msg, void *usrptr) {
+        log_debug("%s", msg);
+}
+
+static char *disk_description(const char *path) {
+        struct udev *udev = NULL;
+        struct udev_device *device = NULL;
+        struct stat st;
+        char *description = NULL;
+        const char *model;
+
+        assert(path);
+
+        if (stat(path, &st) < 0)
+                return NULL;
+
+        if (!S_ISBLK(st.st_mode))
+                return NULL;
+
+        if (!(udev = udev_new()))
+                return NULL;
+
+        if (!(device = udev_device_new_from_devnum(udev, 'b', st.st_rdev)))
+                goto finish;
+
+        if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) ||
+            (model = udev_device_get_property_value(device, "ID_MODEL")) ||
+            (model = udev_device_get_property_value(device, "DM_NAME")))
+                description = strdup(model);
+
+finish:
+        if (device)
+                udev_device_unref(device);
+
+        if (udev)
+                udev_unref(udev);
+
+        return description;
+}
+
+static char *disk_mount_point(const char *label) {
+        char *mp = NULL, *device = NULL;
+        FILE *f = NULL;
+        struct mntent *m;
+
+        /* Yeah, we don't support native systemd unit files here for now */
+
+        if (asprintf(&device, "/dev/mapper/%s", label) < 0)
+                goto finish;
+
+        if (!(f = setmntent("/etc/fstab", "r")))
+                goto finish;
+
+        while ((m = getmntent(f)))
+                if (path_equal(m->mnt_fsname, device)) {
+                        mp = strdup(m->mnt_dir);
+                        break;
+                }
+
+finish:
+        if (f)
+                endmntent(f);
+
+        free(device);
+
+        return mp;
+}
+
+static int help(void) {
+
+        printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
+               "%s detach VOLUME\n\n"
+               "Attaches or detaches an encrypted block device.\n",
+               program_invocation_short_name,
+               program_invocation_short_name);
+
+        return 0;
+}
+
+int main(int argc, char *argv[]) {
+        int r = EXIT_FAILURE;
+        struct crypt_device *cd = NULL;
+        char **passwords = NULL, *truncated_cipher = NULL;
+        const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
+        char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
+        unsigned keyfile_size = 0;
+
+        if (argc <= 1) {
+                help();
+                return EXIT_SUCCESS;
+        }
+
+        if (argc < 3) {
+                log_error("This program requires at least two arguments.");
+                return EXIT_FAILURE;
+        }
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        if (streq(argv[1], "attach")) {
+                uint32_t flags = 0;
+                int k;
+                unsigned try;
+                const char *key_file = NULL;
+                usec_t until;
+                crypt_status_info status;
+
+                /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
+
+                if (argc < 4) {
+                        log_error("attach requires at least two arguments.");
+                        goto finish;
+                }
+
+                if (argc >= 5 &&
+                    argv[4][0] &&
+                    !streq(argv[4], "-") &&
+                    !streq(argv[4], "none")) {
+
+                        if (!path_is_absolute(argv[4]))
+                                log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
+                        else
+                                key_file = argv[4];
+                }
+
+                if (argc >= 6 && argv[5][0] && !streq(argv[5], "-"))
+                        parse_options(argv[5]);
+
+                /* A delicious drop of snake oil */
+                mlockall(MCL_FUTURE);
+
+                description = disk_description(argv[3]);
+                mount_point = disk_mount_point(argv[2]);
+
+                if (description && streq(argv[2], description)) {
+                        /* If the description string is simply the
+                         * volume name, then let's not show this
+                         * twice */
+                        free(description);
+                        description = NULL;
+                }
+
+                if (mount_point && description)
+                        asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
+                else if (mount_point)
+                        asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
+                else if (description)
+                        asprintf(&name_buffer, "%s (%s)", description, argv[2]);
+
+                name = name_buffer ? name_buffer : argv[2];
+
+                if ((k = crypt_init(&cd, argv[3]))) {
+                        log_error("crypt_init() failed: %s", strerror(-k));
+                        goto finish;
+                }
+
+                crypt_set_log_callback(cd, log_glue, NULL);
+
+                status = crypt_status(cd, argv[2]);
+                if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
+                        log_info("Volume %s already active.", argv[2]);
+                        r = EXIT_SUCCESS;
+                        goto finish;
+                }
+
+                if (opt_readonly)
+                        flags |= CRYPT_ACTIVATE_READONLY;
+
+                if (opt_timeout > 0)
+                        until = now(CLOCK_MONOTONIC) + opt_timeout;
+                else
+                        until = 0;
+
+                opt_tries = opt_tries > 0 ? opt_tries : 3;
+                opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
+                hash = opt_hash ? opt_hash : "ripemd160";
+
+                if (opt_cipher) {
+                        size_t l;
+
+                        l = strcspn(opt_cipher, "-");
+
+                        if (!(truncated_cipher = strndup(opt_cipher, l))) {
+                                log_error("Out of memory");
+                                goto finish;
+                        }
+
+                        cipher = truncated_cipher;
+                        cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
+                } else {
+                        cipher = "aes";
+                        cipher_mode = "cbc-essiv:sha256";
+                }
+
+                for (try = 0; try < opt_tries; try++) {
+                        bool pass_volume_key = false;
+
+                        strv_free(passwords);
+                        passwords = NULL;
+
+                        if (!key_file) {
+                                char *text;
+                                char **p;
+
+                                if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
+                                        log_error("Out of memory");
+                                        goto finish;
+                                }
+
+                                k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
+                                free(text);
+
+                                if (k < 0) {
+                                        log_error("Failed to query password: %s", strerror(-k));
+                                        goto finish;
+                                }
+
+                                if (opt_verify) {
+                                        char **passwords2 = NULL;
+
+                                        assert(strv_length(passwords) == 1);
+
+                                        if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
+                                                log_error("Out of memory");
+                                                goto finish;
+                                        }
+
+                                        k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
+                                        free(text);
+
+                                        if (k < 0) {
+                                                log_error("Failed to query verification password: %s", strerror(-k));
+                                                goto finish;
+                                        }
+
+                                        assert(strv_length(passwords2) == 1);
+
+                                        if (!streq(passwords[0], passwords2[0])) {
+                                                log_warning("Passwords did not match, retrying.");
+                                                strv_free(passwords2);
+                                                continue;
+                                        }
+
+                                        strv_free(passwords2);
+                                }
+
+                                strv_uniq(passwords);
+
+                                STRV_FOREACH(p, passwords) {
+                                        char *c;
+
+                                        if (strlen(*p)+1 >= opt_key_size)
+                                                continue;
+
+                                        /* Pad password if necessary */
+                                        if (!(c = new(char, opt_key_size))) {
+                                                log_error("Out of memory.");
+                                                goto finish;
+                                        }
+
+                                        strncpy(c, *p, opt_key_size);
+                                        free(*p);
+                                        *p = c;
+                                }
+                        }
+
+                        k = 0;
+
+                        if (!opt_type || streq(opt_type, CRYPT_LUKS1))
+                                k = crypt_load(cd, CRYPT_LUKS1, NULL);
+
+                        if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
+                                struct crypt_params_plain params;
+
+                                zero(params);
+                                params.hash = hash;
+
+                                /* In contrast to what the name
+                                 * crypt_setup() might suggest this
+                                 * doesn't actually format anything,
+                                 * it just configures encryption
+                                 * parameters when used for plain
+                                 * mode. */
+                                k = crypt_format(cd, CRYPT_PLAIN,
+                                                 cipher,
+                                                 cipher_mode,
+                                                 NULL,
+                                                 NULL,
+                                                 opt_key_size / 8,
+                                                 &params);
+
+                                pass_volume_key = streq(hash, "plain");
+
+                               /* for CRYPT_PLAIN limit reads
+                                * from keyfile to key length */
+                                keyfile_size = opt_key_size / 8;
+                        }
+
+                        if (k < 0) {
+                                log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
+                                goto finish;
+                        }
+
+                        log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
+                                 crypt_get_cipher(cd),
+                                 crypt_get_cipher_mode(cd),
+                                 crypt_get_volume_key_size(cd)*8,
+                                 argv[3]);
+
+                        if (key_file)
+                                k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size, flags);
+                        else {
+                                char **p;
+
+                                STRV_FOREACH(p, passwords) {
+
+                                        if (pass_volume_key)
+                                                k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
+                                        else
+                                                k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
+
+                                        if (k >= 0)
+                                                break;
+                                }
+                        }
+
+                        if (k >= 0)
+                                break;
+
+                        if (k != -EPERM) {
+                                log_error("Failed to activate: %s", strerror(-k));
+                                goto finish;
+                        }
+
+                        log_warning("Invalid passphrase.");
+                }
+
+                if (try >= opt_tries) {
+                        log_error("Too many attempts.");
+                        r = EXIT_FAILURE;
+                        goto finish;
+                }
+
+        } else if (streq(argv[1], "detach")) {
+                int k;
+
+                if ((k = crypt_init_by_name(&cd, argv[2]))) {
+                        log_error("crypt_init() failed: %s", strerror(-k));
+                        goto finish;
+                }
+
+                crypt_set_log_callback(cd, log_glue, NULL);
+
+                if ((k = crypt_deactivate(cd, argv[2])) < 0) {
+                        log_error("Failed to deactivate: %s", strerror(-k));
+                        goto finish;
+                }
+
+        } else {
+                log_error("Unknown verb %s.", argv[1]);
+                goto finish;
+        }
+
+        r = EXIT_SUCCESS;
+
+finish:
+
+        if (cd)
+                crypt_free(cd);
+
+        free(opt_cipher);
+        free(opt_hash);
+
+        free(truncated_cipher);
+
+        strv_free(passwords);
+
+        free(description);
+        free(mount_point);
+        free(name_buffer);
+
+        return r;
+}



More information about the systemd-commits mailing list