[systemd-commits] 11 commits - fixme .gitignore Makefile.am man/daemon.xml man/telinit.xml src/auto-console-getty.c src/auto-serial-getty.c src/dbus-manager.c src/fdset.c src/kmsg-syslogd.c src/log.c src/logger.c src/main.c src/manager.h src/mount.c src/swap.c src/system.conf src/systemctl.c src/update-utmp.c src/util.c src/util.h units/emergency.service units/fedora units/getty at .service.m4 units/.gitignore units/serial-getty at .service.m4 units/systemd-auto-console-getty.service.in units/systemd-auto-serial-getty.service units/systemd-kmsg-syslogd.service.in units/systemd-kmsg-syslogd.socket

Lennart Poettering lennart at kemper.freedesktop.org
Tue Aug 24 18:15:43 PDT 2010


 .gitignore                                  |    3 
 Makefile.am                                 |   37 +
 fixme                                       |   32 +
 man/daemon.xml                              |    2 
 man/telinit.xml                             |    4 
 src/auto-console-getty.c                    |  189 ---------
 src/auto-serial-getty.c                     |  189 +++++++++
 src/dbus-manager.c                          |    6 
 src/fdset.c                                 |    2 
 src/kmsg-syslogd.c                          |  545 ++++++++++++++++++++++++++++
 src/log.c                                   |   22 -
 src/logger.c                                |    7 
 src/main.c                                  |   29 -
 src/manager.h                               |    4 
 src/mount.c                                 |    7 
 src/swap.c                                  |    4 
 src/system.conf                             |    5 
 src/systemctl.c                             |   77 +++
 src/update-utmp.c                           |    4 
 src/util.c                                  |   57 ++
 src/util.h                                  |    4 
 units/.gitignore                            |    2 
 units/emergency.service                     |    2 
 units/fedora/prefdm.service                 |    2 
 units/fedora/single.service                 |    2 
 units/getty at .service.m4                     |    2 
 units/serial-getty at .service.m4              |   37 +
 units/systemd-auto-console-getty.service.in |   16 
 units/systemd-auto-serial-getty.service     |   16 
 units/systemd-kmsg-syslogd.service.in       |   16 
 units/systemd-kmsg-syslogd.socket           |   20 +
 31 files changed, 1063 insertions(+), 281 deletions(-)

New commits:
commit 1a7fdcad3ae37fae7789584d203eca97bf0a223a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:15:32 2010 +0200

    units: make sure prefdm is automatically respawned

diff --git a/units/fedora/prefdm.service b/units/fedora/prefdm.service
index 931b47f..22ee54d 100644
--- a/units/fedora/prefdm.service
+++ b/units/fedora/prefdm.service
@@ -15,6 +15,8 @@ Conflicts=getty at tty1.service plymouth-quit.service
 
 [Service]
 ExecStart=/etc/X11/prefdm -nodaemon
+Restart=restart-always
+RestartSec=0
 
 [Install]
 Alias=display-manager.service
commit ddad68097d307fd8cdfd06946691211fb65b74e3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:15:12 2010 +0200

    units: invoke sulogin instead of /bin/sh

diff --git a/units/emergency.service b/units/emergency.service
index dda7e16..4a1e31a 100644
--- a/units/emergency.service
+++ b/units/emergency.service
@@ -14,7 +14,7 @@ DefaultDependencies=no
 [Service]
 ExecStartPre=-/bin/plymouth --hide-splash
 ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" to activate default mode.'
-ExecStart=/bin/sh
+ExecStart=-/sbin/sulogin
 StandardInput=tty-force
 Restart=restart-always
 RestartSec=0
diff --git a/units/fedora/single.service b/units/fedora/single.service
index 75b8ecc..2eba886 100644
--- a/units/fedora/single.service
+++ b/units/fedora/single.service
@@ -17,7 +17,7 @@ Before=multi-user.target
 [Service]
 ExecStartPre=-/bin/plymouth --hide-splash
 ExecStartPre=-/bin/echo 'Welcome to rescue mode. Use "systemctl default" to activate default mode.'
-ExecStart=/bin/sh
+ExecStart=-/sbin/sulogin
 StandardInput=tty-force
 Restart=restart-always
 RestartSec=0
commit 3006982d93e92019dd6d94a7518684593b43a05e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:14:53 2010 +0200

    utmp: write out runlevels 5 and 3 preferrably if multiples make sense, and S instead of 1

diff --git a/src/update-utmp.c b/src/update-utmp.c
index 5a48bd9..3ec0a16 100644
--- a/src/update-utmp.c
+++ b/src/update-utmp.c
@@ -116,10 +116,10 @@ static int get_current_runlevel(Context *c) {
                 /* The first target of this list that is active or has
                  * a job scheduled wins */
                 { '5', SPECIAL_RUNLEVEL5_TARGET },
-                { '4', SPECIAL_RUNLEVEL4_TARGET },
                 { '3', SPECIAL_RUNLEVEL3_TARGET },
+                { '4', SPECIAL_RUNLEVEL4_TARGET },
                 { '2', SPECIAL_RUNLEVEL2_TARGET },
-                { '1', SPECIAL_RESCUE_TARGET },
+                { 'S', SPECIAL_RESCUE_TARGET },
         };
         const char
                 *interface = "org.freedesktop.systemd1.Unit",
commit f3d41013e24a81b2c853393593d1d52c156826ec
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:14:04 2010 +0200

    systemctl: rename a few status lines

diff --git a/src/systemctl.c b/src/systemctl.c
index 0c33abb..9da8303 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1613,7 +1613,7 @@ static void print_status_info(UnitStatusInfo *i) {
                         continue;
 
                 t = strv_join(p->argv, " ");
-                printf("\t  Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
+                printf("\t Process: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
                 free(t);
 
                 if (p->code == CLD_EXITED) {
@@ -1642,7 +1642,7 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("\t");
 
                 if (i->main_pid > 0) {
-                        printf("    Main: %u", (unsigned) i->main_pid);
+                        printf("Main PID: %u", (unsigned) i->main_pid);
 
                         if (i->running) {
                                 char *t = NULL;
commit 584be568b99633eb48c21ece92e241de011ecc9a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:13:44 2010 +0200

    systemctl: show timestamps for state changes

diff --git a/src/systemctl.c b/src/systemctl.c
index f9317ad..0c33abb 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -1489,6 +1489,11 @@ typedef struct UnitStatusInfo {
         const char *path;
         const char *default_control_group;
 
+        usec_t inactive_exit_timestamp;
+        usec_t active_enter_timestamp;
+        usec_t active_exit_timestamp;
+        usec_t inactive_enter_timestamp;
+
         bool need_daemon_reload;
 
         /* Service */
@@ -1523,6 +1528,9 @@ typedef struct UnitStatusInfo {
 static void print_status_info(UnitStatusInfo *i) {
         ExecStatusInfo *p;
         const char *on, *off, *ss;
+        usec_t timestamp;
+        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+        char since2[FORMAT_TIMESTAMP_MAX], *s2;
 
         assert(i);
 
@@ -1559,17 +1567,34 @@ static void print_status_info(UnitStatusInfo *i) {
                 on = off = "";
 
         if (ss)
-                printf("\t  Active: %s%s (%s)%s\n",
+                printf("\t  Active: %s%s (%s)%s",
                        on,
                        strna(i->active_state),
                        ss,
                        off);
         else
-                printf("\t  Active: %s%s%s\n",
+                printf("\t  Active: %s%s%s",
                        on,
                        strna(i->active_state),
                        off);
 
+        timestamp = (streq_ptr(i->active_state, "active")      ||
+                     streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
+                    (streq_ptr(i->active_state, "inactive")    ||
+                     streq_ptr(i->active_state, "maintenance")) ? i->inactive_enter_timestamp :
+                    streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
+                                                                  i->active_exit_timestamp;
+
+        s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
+        s2 = format_timestamp(since2, sizeof(since2), timestamp);
+
+        if (s1)
+                printf(" since [%s; %s]\n", s2, s1);
+        else if (s2)
+                printf(" since [%s]\n", s2);
+        else
+                printf("\n");
+
         if (i->sysfs_path)
                 printf("\t  Device: %s\n", i->sysfs_path);
         else if (i->where)
@@ -1782,6 +1807,14 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                         i->start_timestamp = (usec_t) u;
                 else if (streq(name, "ExecMainExitTimestamp"))
                         i->exit_timestamp = (usec_t) u;
+                else if (streq(name, "ActiveEnterTimestamp"))
+                        i->active_enter_timestamp = (usec_t) u;
+                else if (streq(name, "InactiveEnterTimestamp"))
+                        i->inactive_enter_timestamp = (usec_t) u;
+                else if (streq(name, "InactiveExitTimestamp"))
+                        i->inactive_exit_timestamp = (usec_t) u;
+                else if (streq(name, "ActiveExitTimestamp"))
+                        i->active_exit_timestamp = (usec_t) u;
 
                 break;
         }
diff --git a/src/util.c b/src/util.c
index f1a7bbd..a09b704 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1659,6 +1659,63 @@ char *format_timestamp(char *buf, size_t l, usec_t t) {
         return buf;
 }
 
+char *format_timestamp_pretty(char *buf, size_t l, usec_t t) {
+        usec_t n, d;
+
+        n = now(CLOCK_REALTIME);
+
+        if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
+                return NULL;
+
+        d = n - t;
+
+        if (d >= USEC_PER_YEAR)
+                snprintf(buf, l, "%llu years and %llu months ago",
+                         (unsigned long long) (d / USEC_PER_YEAR),
+                         (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
+        else if (d >= USEC_PER_MONTH)
+                snprintf(buf, l, "%llu months and %llu days ago",
+                         (unsigned long long) (d / USEC_PER_MONTH),
+                         (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
+        else if (d >= USEC_PER_WEEK)
+                snprintf(buf, l, "%llu weeks and %llu days ago",
+                         (unsigned long long) (d / USEC_PER_WEEK),
+                         (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
+        else if (d >= 2*USEC_PER_DAY)
+                snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
+        else if (d >= 25*USEC_PER_HOUR)
+                snprintf(buf, l, "1 day and %lluh ago",
+                         (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
+        else if (d >= 6*USEC_PER_HOUR)
+                snprintf(buf, l, "%lluh ago",
+                         (unsigned long long) (d / USEC_PER_HOUR));
+        else if (d >= USEC_PER_HOUR)
+                snprintf(buf, l, "%lluh %llumin ago",
+                         (unsigned long long) (d / USEC_PER_HOUR),
+                         (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
+        else if (d >= 5*USEC_PER_MINUTE)
+                snprintf(buf, l, "%llumin ago",
+                         (unsigned long long) (d / USEC_PER_MINUTE));
+        else if (d >= USEC_PER_MINUTE)
+                snprintf(buf, l, "%llumin %llus ago",
+                         (unsigned long long) (d / USEC_PER_MINUTE),
+                         (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
+        else if (d >= USEC_PER_SEC)
+                snprintf(buf, l, "%llus ago",
+                         (unsigned long long) (d / USEC_PER_SEC));
+        else if (d >= USEC_PER_MSEC)
+                snprintf(buf, l, "%llums ago",
+                         (unsigned long long) (d / USEC_PER_MSEC));
+        else if (d > 0)
+                snprintf(buf, l, "%lluus ago",
+                         (unsigned long long) d);
+        else
+                snprintf(buf, l, "now");
+
+        buf[l-1] = 0;
+        return buf;
+}
+
 char *format_timespan(char *buf, size_t l, usec_t t) {
         static const struct {
                 const char *suffix;
diff --git a/src/util.h b/src/util.h
index 4063ee7..3a7ac29 100644
--- a/src/util.h
+++ b/src/util.h
@@ -52,12 +52,15 @@ typedef struct dual_timestamp {
 #define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE)
 #define USEC_PER_DAY (24ULL*USEC_PER_HOUR)
 #define USEC_PER_WEEK (7ULL*USEC_PER_DAY)
+#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC)
+#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC)
 
 /* What is interpreted as whitespace? */
 #define WHITESPACE " \t\n\r"
 #define NEWLINE "\n\r"
 
 #define FORMAT_TIMESTAMP_MAX 64
+#define FORMAT_TIMESTAMP_PRETTY_MAX 256
 #define FORMAT_TIMESPAN_MAX 64
 
 #define ANSI_HIGHLIGHT_ON "\x1B[1;31m"
@@ -248,6 +251,7 @@ bool ignore_file(const char *filename);
 bool chars_intersect(const char *a, const char *b);
 
 char *format_timestamp(char *buf, size_t l, usec_t t);
+char *format_timestamp_pretty(char *buf, size_t l, usec_t t);
 char *format_timespan(char *buf, size_t l, usec_t t);
 
 int make_stdio(int fd);
commit f1e36d677ac771408e40c34ead368a7fdbcc0622
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:13:09 2010 +0200

    systemctl: add --sysv-compat

diff --git a/src/systemctl.c b/src/systemctl.c
index 30f6b2a..f9317ad 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -69,6 +69,11 @@ static bool arg_quiet = false;
 static bool arg_full = false;
 static bool arg_force = false;
 static bool arg_defaults = false;
+static bool arg_sysv_compat = false; /* this is undocumented, and
+                                      * exists simply to make
+                                      * implementation of SysV
+                                      * compatible shell glue
+                                      * easier */
 static char **arg_wall = NULL;
 static usec_t arg_when = 0;
 static enum action {
@@ -1359,7 +1364,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
                 if (!arg_quiet)
                         puts(state);
 
-                if (streq(state, "active") || startswith(state, "reloading"))
+                if (streq(state, "active") || streq(state, "reloading"))
                         r = 0;
 
                 dbus_message_unref(m);
@@ -2150,16 +2155,27 @@ static int show_one(DBusConnection *bus, const char *path, bool show_properties,
                 dbus_message_iter_next(&sub);
         }
 
-        if (!show_properties)
-                print_status_info(&info);
+        r = 0;
+
+        if (!show_properties) {
+                if (arg_sysv_compat &&
+                    !streq_ptr(info.active_state, "active") &&
+                    !streq_ptr(info.active_state, "reloading")) {
+
+                        /* If the SysV compatibility mode is on, we
+                         * will refuse to run "status" on units that
+                         * aren't active */
+                        log_error("Unit not active.");
+                        r = -EADDRNOTAVAIL;
+                } else
+                        print_status_info(&info);
+        }
 
         while ((p = info.exec)) {
                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
                 exec_status_info_free(p);
         }
 
-        r = 0;
-
 finish:
         if (m)
                 dbus_message_unref(m);
@@ -3895,7 +3911,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_FULL,
                 ARG_FORCE,
                 ARG_NO_RELOAD,
-                ARG_DEFAULTS
+                ARG_DEFAULTS,
+                ARG_SYSV_COMPAT
         };
 
         static const struct option options[] = {
@@ -3915,7 +3932,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
                 { "force",     no_argument,       NULL, ARG_FORCE     },
                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
-                { "defaults",   no_argument,      NULL, ARG_DEFAULTS  },
+                { "defaults",  no_argument,       NULL, ARG_DEFAULTS  },
+                { "sysv-compat", no_argument,     NULL, ARG_SYSV_COMPAT },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -4009,6 +4027,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_defaults = true;
                         break;
 
+                case ARG_SYSV_COMPAT:
+                        arg_sysv_compat = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
commit 44bcea66542e398fcada22ba9cb24d07bd8e04ef
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:12:19 2010 +0200

    log: SCM_CREDENTIALS will be added by the kernel anyway, so there's no need to write them manually

diff --git a/src/log.c b/src/log.c
index 3c42e8e..21fc9f4 100644
--- a/src/log.c
+++ b/src/log.c
@@ -248,11 +248,6 @@ static int write_to_syslog(
         char header_priority[16], header_time[64], header_pid[16];
         struct iovec iovec[5];
         struct msghdr msghdr;
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-        } control;
-        struct ucred *ucred;
         time_t t;
         struct tm *tm;
 
@@ -279,21 +274,9 @@ static int write_to_syslog(
         IOVEC_SET_STRING(iovec[3], header_pid);
         IOVEC_SET_STRING(iovec[4], buffer);
 
-        zero(control);
-        control.cmsghdr.cmsg_level = SOL_SOCKET;
-        control.cmsghdr.cmsg_type = SCM_CREDENTIALS;
-        control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
-
-        ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
-        ucred->pid = getpid();
-        ucred->uid = getuid();
-        ucred->gid = getgid();
-
         zero(msghdr);
         msghdr.msg_iov = iovec;
         msghdr.msg_iovlen = ELEMENTSOF(iovec);
-        msghdr.msg_control = &control;
-        msghdr.msg_controllen = control.cmsghdr.cmsg_len;
 
         if (sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL) < 0)
                 return -errno;
commit d3689161a2870a56ba5a2837daa2ca3463e24710
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:11:26 2010 +0200

    mount: add global configuration options for handling of auto mounts

diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index eb37684..5571247 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -141,6 +141,9 @@
         "  <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n" \
         "  <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
         "  <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"MountOnPlug\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"SwapOnPlug\" type=\"b\" access=\"read\"/>\n" \
+        "  <property name=\"MountAuto\" type=\"b\" access=\"read\"/>\n" \
         " </interface>\n"
 
 #define INTROSPECTION_BEGIN                                             \
@@ -252,6 +255,9 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
                 { "org.freedesktop.systemd1.Manager", "SysVRcndPath",  bus_property_append_strv,      "as", m->lookup_paths.sysvrcnd_path },
                 { "org.freedesktop.systemd1.Manager", "NotifySocket",  bus_property_append_string,    "s",  m->notify_socket   },
                 { "org.freedesktop.systemd1.Manager", "ControlGroupHierarchy", bus_property_append_string, "s", m->cgroup_hierarchy },
+                { "org.freedesktop.systemd1.Manager", "MountOnPlug",   bus_property_append_bool,      "b",  &m->mount_on_plug  },
+                { "org.freedesktop.systemd1.Manager", "SwapOnPlug",    bus_property_append_bool,      "b",  &m->swap_on_plug   },
+                { "org.freedesktop.systemd1.Manager", "MountAuto",     bus_property_append_bool,      "b",  &m->mount_auto     },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
diff --git a/src/main.c b/src/main.c
index 35ee1c7..54fc054 100644
--- a/src/main.c
+++ b/src/main.c
@@ -64,6 +64,9 @@ static int arg_crash_chvt = -1;
 static bool arg_confirm_spawn = false;
 static bool arg_show_status = true;
 static bool arg_sysv_console = true;
+static bool arg_mount_on_plug = true;
+static bool arg_swap_on_plug = true;
+static bool arg_mount_auto = true;
 
 static FILE* serialization = NULL;
 
@@ -472,16 +475,19 @@ static int config_parse_cpu_affinity(
 static int parse_config_file(void) {
 
         const ConfigItem items[] = {
-                { "LogLevel",    config_parse_level,        NULL,             "Manager" },
-                { "LogTarget",   config_parse_target,       NULL,             "Manager" },
-                { "LogColor",    config_parse_color,        NULL,             "Manager" },
-                { "LogLocation", config_parse_location,     NULL,             "Manager" },
-                { "DumpCore",    config_parse_bool,         &arg_dump_core,   "Manager" },
-                { "CrashShell",  config_parse_bool,         &arg_crash_shell, "Manager" },
-                { "ShowStatus",  config_parse_bool,         &arg_show_status, "Manager" },
-                { "SysVConsole", config_parse_bool,         &arg_sysv_console,"Manager" },
-                { "CrashChVT",   config_parse_int,          &arg_crash_chvt,  "Manager" },
-                { "CPUAffinity", config_parse_cpu_affinity, NULL,             "Manager" },
+                { "LogLevel",    config_parse_level,        NULL,               "Manager" },
+                { "LogTarget",   config_parse_target,       NULL,               "Manager" },
+                { "LogColor",    config_parse_color,        NULL,               "Manager" },
+                { "LogLocation", config_parse_location,     NULL,               "Manager" },
+                { "DumpCore",    config_parse_bool,         &arg_dump_core,     "Manager" },
+                { "CrashShell",  config_parse_bool,         &arg_crash_shell,   "Manager" },
+                { "ShowStatus",  config_parse_bool,         &arg_show_status,   "Manager" },
+                { "SysVConsole", config_parse_bool,         &arg_sysv_console,  "Manager" },
+                { "CrashChVT",   config_parse_int,          &arg_crash_chvt,    "Manager" },
+                { "CPUAffinity", config_parse_cpu_affinity, NULL,               "Manager" },
+                { "MountOnPlug", config_parse_bool,         &arg_mount_on_plug, "Manager" },
+                { "SwapOnPlug",  config_parse_bool,         &arg_swap_on_plug,  "Manager" },
+                { "MountAuto",   config_parse_bool,         &arg_mount_auto,    "Manager" },
                 { NULL, NULL, NULL, NULL }
         };
 
@@ -986,6 +992,9 @@ int main(int argc, char *argv[]) {
         m->confirm_spawn = arg_confirm_spawn;
         m->show_status = arg_show_status;
         m->sysv_console = arg_sysv_console;
+        m->mount_on_plug = arg_mount_on_plug;
+        m->swap_on_plug = arg_swap_on_plug;
+        m->mount_auto = arg_mount_auto;
 
         if ((r = manager_startup(m, serialization, fds)) < 0)
                 log_error("Failed to fully start up daemon: %s", strerror(-r));
diff --git a/src/manager.h b/src/manager.h
index 2b4eee9..dd48593 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -202,6 +202,10 @@ struct Manager {
         bool confirm_spawn;
         bool sysv_console;
 
+        bool mount_on_plug;
+        bool swap_on_plug;
+        bool mount_auto;
+
         int n_deserializing;
 };
 
diff --git a/src/mount.c b/src/mount.c
index b667ae5..b49443c 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -244,7 +244,8 @@ static int mount_add_target_links(Mount *m) {
 
         noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO);
         user = mount_test_option(p->options, "user") || mount_test_option(p->options, "users");
-        handle = !!mount_test_option(p->options, "comment=systemd.mount");
+        handle = !!mount_test_option(p->options, "comment=systemd.mount") ||
+                m->meta.manager->mount_auto;
         automount = !!mount_test_option(p->options, "comment=systemd.automount");
 
         if (mount_test_option(p->options, "_netdev") ||
@@ -362,7 +363,9 @@ static int mount_load(Unit *u) {
                         what = m->parameters_proc_self_mountinfo.what;
 
                 if (what && !path_equal(m->where, "/"))
-                        if ((r = unit_add_node_link(u, what, u->meta.manager->running_as == MANAGER_SYSTEM)) < 0)
+                        if ((r = unit_add_node_link(u, what,
+                                                    u->meta.manager->running_as == MANAGER_SYSTEM &&
+                                                    u->meta.manager->mount_on_plug)) < 0)
                                 return r;
 
                 if ((r = mount_add_mount_links(m)) < 0)
diff --git a/src/swap.c b/src/swap.c
index c81fd67..4a672fb 100644
--- a/src/swap.c
+++ b/src/swap.c
@@ -195,7 +195,9 @@ static int swap_load(Unit *u) {
                         if ((r = unit_set_description(u, s->what)) < 0)
                                 return r;
 
-                if ((r = unit_add_node_link(u, s->what, u->meta.manager->running_as == MANAGER_SYSTEM)) < 0)
+                if ((r = unit_add_node_link(u, s->what,
+                                            u->meta.manager->running_as == MANAGER_SYSTEM &&
+                                            u->meta.manager->swap_on_plug)) < 0)
                         return r;
 
                 if ((r = swap_add_mount_links(s)) < 0)
diff --git a/src/system.conf b/src/system.conf
index 11885e0..9d87c6d 100644
--- a/src/system.conf
+++ b/src/system.conf
@@ -5,7 +5,7 @@
 #  the Free Software Foundation; either version 2 of the License, or
 #  (at your option) any later version.
 #
-# See system.conf(5) for details
+# See systemd(1) for details
 
 [Manager]
 #LogLevel=info
@@ -18,3 +18,6 @@
 #SysVConsole=yes
 #CrashChVT=1
 #CPUAffinity=1 2
+#MountOnPlug=yes
+#SwapOnPlug=yes
+#MountAuto=yes
commit 20604ebc04ce5d3b7d7d63e79f94cf0febf851c5
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:10:13 2010 +0200

    man: minor updates

diff --git a/fixme b/fixme
index 2aa4dc6..56efcaf 100644
--- a/fixme
+++ b/fixme
@@ -58,24 +58,42 @@
 
 * bash completion a la gdbus
 
-* use sulogin
-
 * [Install] section rausmachen für early boot krams, uznd per default nach /lib linken
 
-* s/Exited/Process/ in systemctl status
+* systemctl list-jobs deps anzeigen
 
-* systemctl status: "active since 5min"
+* ConditionFileExists=, ConditionKernelCommandLine=, ConditionEnvironment= mit !
 
-* systemctl list-jobs deps anzeigen
+* oom_score_adj
 
-* /etc/systemd/system.conf: mounten per default option
+* accountsservice is dod
 
-* ConditionFileExists=, ConditionKernelCommandLine=, ConditionEnvironment= mit !
+* follow LSB exit codes spec in "systemctl start"
+
+* auditd service files
+
+* override the human readable dbus error code for permission denied.
+
+* discuss reexec on shutdown, async. vs. sync?
+
+* auto-serial-getty vs. isolate
+
+* add RefuseManualIsolate= (default on?)
+
+* add systemctl switch to dump transaction without executing it
+
+* shell wenn fsck im arsch is
+
+* system.conf/session.conf brauch ne man page
 
 External:
 
+* make sure MountOnPlug und MountAuto und SwapOnPlug is off in Fedora
+
 * place /etc/inittab with explaining blurb.
 
+* pam_securetty should honour console=
+
 * procps, psmisc, sysvinit-tools, hostname → util-linux-ng
 
 * nologin nach /var/run https://bugzilla.redhat.com/show_bug.cgi?id=624489
diff --git a/man/daemon.xml b/man/daemon.xml
index b8e9df4..fdc6a64 100644
--- a/man/daemon.xml
+++ b/man/daemon.xml
@@ -449,7 +449,7 @@
                         activation of daemons. However, the primary
                         advantage of this scheme is that all providers
                         and all consumers of the sockets can be
-                        started in parallel as soon als all sockets
+                        started in parallel as soon as all sockets
                         are established. In addition to that daemons
                         can be restarted with losing only a minimal
                         number of client transactions or even any
diff --git a/man/telinit.xml b/man/telinit.xml
index bbf43bf..fec059a 100644
--- a/man/telinit.xml
+++ b/man/telinit.xml
@@ -124,9 +124,9 @@
                                 <filename>runlevel2.target</filename>,
                                 <filename>runlevel3.target</filename>,
                                 ... and is equivalent to
-                                <command>systemctl start
+                                <command>systemctl isolate
                                 runlevel2.target</command>,
-                                <command>systemctl start
+                                <command>systemctl isolate
                                 runlevel3.target</command>,
                                 ...</para></listitem>
                         </varlistentry>
commit 93a45c562a1989dfbb2dd08c65f8a21b02959934
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Aug 25 03:09:57 2010 +0200

    serial: use seperate getty template for serial ttys

diff --git a/.gitignore b/.gitignore
index 1cee1b6..2c92ae0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@ systemd-kmsg-syslogd
 systemd-remount-api-vfs
 test-hostname
 systemd-modules-load
-systemd-auto-console-getty
+systemd-auto-serial-getty
 systemd-shutdownd
 systemd-random-seed
 systemd-update-utmp
diff --git a/Makefile.am b/Makefile.am
index aa2998d..859d332 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -73,7 +73,7 @@ rootlibexec_PROGRAMS = \
 	systemd-update-utmp \
 	systemd-random-seed \
 	systemd-shutdownd \
-	systemd-auto-console-getty \
+	systemd-auto-serial-getty \
 	systemd-modules-load \
 	systemd-remount-api-vfs \
 	systemd-kmsg-syslogd
@@ -171,6 +171,7 @@ dist_systemunit_DATA = \
 nodist_systemunit_DATA = \
 	units/sysinit.target \
 	units/getty at .service \
+	units/serial-getty at .service \
 	units/graphical.target \
 	units/remote-fs.target \
 	units/multi-user.target \
@@ -178,7 +179,7 @@ nodist_systemunit_DATA = \
 	units/systemd-logger.service \
 	units/systemd-shutdownd.service \
 	units/systemd-kmsg-syslogd.service \
-	units/systemd-auto-console-getty.service \
+	units/systemd-auto-serial-getty.service \
 	units/systemd-modules-load.service \
 	units/systemd-remount-api-vfs.service \
 	units/systemd-update-utmp-runlevel.service \
@@ -197,6 +198,7 @@ nodist_sessionunit_DATA = \
 EXTRA_DIST = \
 	units/sysinit.target.m4 \
 	units/getty at .service.m4 \
+	units/serial-getty at .service.m4 \
 	units/graphical.target.m4 \
 	units/multi-user.target.m4 \
 	units/remote-fs.target.m4 \
@@ -204,7 +206,7 @@ EXTRA_DIST = \
 	units/systemd-logger.service.in \
 	units/systemd-shutdownd.service.in \
 	units/systemd-kmsg-syslogd.service.in \
-	units/systemd-auto-console-getty.service.in \
+	units/systemd-auto-serial-getty.service.in \
 	units/systemd-modules-load.service.in \
 	units/systemd-remount-api-vfs.service.in \
 	units/systemd-update-utmp-runlevel.service.in \
@@ -573,15 +575,15 @@ systemd_shutdownd_CFLAGS = \
 systemd_shutdownd_LDADD = \
 	libsystemd-basic.la
 
-systemd_auto_console_getty_SOURCES = \
-	src/auto-console-getty.c \
+systemd_auto_serial_getty_SOURCES = \
+	src/auto-serial-getty.c \
 	src/dbus-common.c
 
-systemd_auto_console_getty_CFLAGS = \
+systemd_auto_serial_getty_CFLAGS = \
 	$(AM_CFLAGS) \
 	$(DBUS_CFLAGS)
 
-systemd_auto_console_getty_LDADD = \
+systemd_auto_serial_getty_LDADD = \
 	libsystemd-basic.la \
 	$(DBUS_LIBS)
 
@@ -896,14 +898,14 @@ install-data-hook:
 		$(LN_S) $(systemunitdir)/reboot.target ctrl-alt-del.target && \
 		$(LN_S) $(systemunitdir)/rescue.target kbrequest.target )
 	( cd $(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants && \
-		rm -f getty at tty1.service getty at tty2.service getty at tty3.service getty at tty4.service getty at tty5.service getty at tty6.service systemd-auto-console-getty.service && \
+		rm -f getty at tty1.service getty at tty2.service getty at tty3.service getty at tty4.service getty at tty5.service getty at tty6.service systemd-auto-serial-getty.service && \
 		$(LN_S) $(systemunitdir)/getty at .service getty at tty1.service && \
 		$(LN_S) $(systemunitdir)/getty at .service getty at tty2.service && \
 		$(LN_S) $(systemunitdir)/getty at .service getty at tty3.service && \
 		$(LN_S) $(systemunitdir)/getty at .service getty at tty4.service && \
 		$(LN_S) $(systemunitdir)/getty at .service getty at tty5.service && \
 		$(LN_S) $(systemunitdir)/getty at .service getty at tty6.service && \
-		$(LN_S) $(systemunitdir)/systemd-auto-console-getty.service systemd-auto-console-getty.service )
+		$(LN_S) $(systemunitdir)/systemd-auto-serial-getty.service systemd-auto-serial-getty.service )
 	( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \
 		rm -f getty.target remote-fs.target && \
 		$(LN_S) $(systemunitdir)/getty.target getty.target && \
diff --git a/src/auto-console-getty.c b/src/auto-console-getty.c
deleted file mode 100644
index 44d2eff..0000000
--- a/src/auto-console-getty.c
+++ /dev/null
@@ -1,189 +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 <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <dbus/dbus.h>
-
-#include "util.h"
-#include "log.h"
-#include "dbus-common.h"
-
-static int spawn_getty(DBusConnection *bus, const char *console) {
-        DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
-        const char *fail = "fail";
-        char *name;
-        int r = -EIO;
-
-        dbus_error_init(&error);
-
-        assert(bus);
-        assert(console);
-
-        /* FIXME: we probably should escape the tty name properly here */
-        if (asprintf(&name, "getty@%s.service", console) < 0)
-                return -ENOMEM;
-
-        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"))) {
-                log_error("Could not allocate message.");
-                goto finish;
-        }
-
-        if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &name,
-                                      DBUS_TYPE_STRING, &fail,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not attach target and flag information to message.");
-                goto finish;
-        }
-
-        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to start unit: %s", error.message);
-                goto finish;
-        }
-
-        r = 0;
-
-finish:
-        if (m)
-                dbus_message_unref(m);
-
-        if (reply)
-                dbus_message_unref(reply);
-
-        dbus_error_free(&error);
-
-        free(name);
-
-        return r;
-}
-
-static int parse_proc_cmdline_word(const char *word, char **console) {
-        assert(word);
-
-        if (startswith(word, "console=")) {
-                const char *k;
-                size_t l;
-                char *w = NULL;
-
-                k = word + 8;
-                l = strcspn(k, ",");
-
-                if (l < 4 ||
-                    !startswith(k, "tty") ||
-                    k[3+strspn(k+3, "0123456789")] != 0) {
-
-                        if (!(w = strndup(k, l)))
-                                return -ENOMEM;
-
-                }
-
-                free(*console);
-                *console = w;
-        }
-
-        return 0;
-}
-
-static int parse_proc_cmdline(char **console) {
-        char *line;
-        int r;
-        char *w;
-        size_t l;
-        char *state;
-
-        assert(console);
-
-        if ((r = read_one_line_file("/tmp/cmdline", &line)) < 0) {
-                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
-                return 0;
-        }
-
-        FOREACH_WORD_QUOTED(w, l, line, state) {
-                char *word;
-
-                if (!(word = strndup(w, l))) {
-                        r = -ENOMEM;
-                        goto finish;
-                }
-
-                r = parse_proc_cmdline_word(word, console);
-                free(word);
-
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = 0;
-
-finish:
-        free(line);
-        return r;
-}
-
-int main(int argc, char *argv[]) {
-        DBusError error;
-        int r = 1;
-        char *console = NULL;
-        DBusConnection *bus = NULL;
-
-        dbus_error_init(&error);
-
-        if (argc > 1) {
-                log_error("This program does not take arguments.");
-                return 1;
-        }
-
-        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
-        log_parse_environment();
-        log_open();
-
-        if (bus_connect(DBUS_BUS_SYSTEM, &bus, NULL, &error) < 0) {
-                log_error("Failed to get D-Bus connection: %s", error.message);
-                goto finish;
-        }
-
-        if (parse_proc_cmdline(&console) < 0)
-                goto finish;
-
-        if (console)
-                if (spawn_getty(bus, console) < 0)
-                        goto finish;
-
-        r = 0;
-
-finish:
-        free(console);
-
-        if (bus) {
-               dbus_connection_close(bus);
-               dbus_connection_unref(bus);
-        }
-
-        dbus_error_free(&error);
-
-        dbus_shutdown();
-
-        return r;
-}
diff --git a/src/auto-serial-getty.c b/src/auto-serial-getty.c
new file mode 100644
index 0000000..7bc2fba
--- /dev/null
+++ b/src/auto-serial-getty.c
@@ -0,0 +1,189 @@
+/*-*- 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 <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dbus/dbus.h>
+
+#include "util.h"
+#include "log.h"
+#include "dbus-common.h"
+
+static int spawn_getty(DBusConnection *bus, const char *console) {
+        DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        const char *fail = "fail";
+        char *name;
+        int r = -EIO;
+
+        dbus_error_init(&error);
+
+        assert(bus);
+        assert(console);
+
+        /* FIXME: we probably should escape the tty name properly here */
+        if (asprintf(&name, "serial-getty@%s.service", console) < 0)
+                return -ENOMEM;
+
+        if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"))) {
+                log_error("Could not allocate message.");
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &name,
+                                      DBUS_TYPE_STRING, &fail,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not attach target and flag information to message.");
+                goto finish;
+        }
+
+        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                log_error("Failed to start unit: %s", error.message);
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        dbus_error_free(&error);
+
+        free(name);
+
+        return r;
+}
+
+static int parse_proc_cmdline_word(const char *word, char **console) {
+        assert(word);
+
+        if (startswith(word, "console=")) {
+                const char *k;
+                size_t l;
+                char *w = NULL;
+
+                k = word + 8;
+                l = strcspn(k, ",");
+
+                if (l < 4 ||
+                    !startswith(k, "tty") ||
+                    k[3+strspn(k+3, "0123456789")] != 0) {
+
+                        if (!(w = strndup(k, l)))
+                                return -ENOMEM;
+
+                }
+
+                free(*console);
+                *console = w;
+        }
+
+        return 0;
+}
+
+static int parse_proc_cmdline(char **console) {
+        char *line;
+        int r;
+        char *w;
+        size_t l;
+        char *state;
+
+        assert(console);
+
+        if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
+                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
+                return 0;
+        }
+
+        FOREACH_WORD_QUOTED(w, l, line, state) {
+                char *word;
+
+                if (!(word = strndup(w, l))) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                r = parse_proc_cmdline_word(word, console);
+                free(word);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        free(line);
+        return r;
+}
+
+int main(int argc, char *argv[]) {
+        DBusError error;
+        int r = 1;
+        char *console = NULL;
+        DBusConnection *bus = NULL;
+
+        dbus_error_init(&error);
+
+        if (argc > 1) {
+                log_error("This program does not take arguments.");
+                return 1;
+        }
+
+        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        log_parse_environment();
+        log_open();
+
+        if (bus_connect(DBUS_BUS_SYSTEM, &bus, NULL, &error) < 0) {
+                log_error("Failed to get D-Bus connection: %s", error.message);
+                goto finish;
+        }
+
+        if (parse_proc_cmdline(&console) < 0)
+                goto finish;
+
+        if (console)
+                if (spawn_getty(bus, console) < 0)
+                        goto finish;
+
+        r = 0;
+
+finish:
+        free(console);
+
+        if (bus) {
+               dbus_connection_close(bus);
+               dbus_connection_unref(bus);
+        }
+
+        dbus_error_free(&error);
+
+        dbus_shutdown();
+
+        return r;
+}
diff --git a/units/.gitignore b/units/.gitignore
index 82a2417..35f7908 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,4 @@
+serial-getty at .service
 systemd-kmsg-syslogd.service
 systemd-modules-load.service
 systemd-remount-api-vfs.service
diff --git a/units/getty at .service.m4 b/units/getty at .service.m4
index 01343c4..4b65d5b 100644
--- a/units/getty at .service.m4
+++ b/units/getty at .service.m4
@@ -30,7 +30,7 @@ Before=getty.target
 
 [Service]
 Environment=TERM=linux
-ExecStart=GETTY %I
+ExecStart=-GETTY %I
 Restart=restart-always
 RestartSec=0
 KillMode=process-group
diff --git a/units/serial-getty at .service.m4 b/units/serial-getty at .service.m4
new file mode 100644
index 0000000..b91ed98
--- /dev/null
+++ b/units/serial-getty at .service.m4
@@ -0,0 +1,37 @@
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Serial Getty on %I
+Requires=dev-%i.device
+After=dev-%i.device
+m4_ifdef(`TARGET_FEDORA',
+After=rc-local.service
+)m4_dnl
+m4_ifdef(`TARGET_ARCH',
+After=rc-local.service
+)m4_dnl
+
+# If additional gettys are spawned during boot (possibly by
+# systemd-auto-console-getty) then we should make sure that this is
+# synchronized before getty.target, even though getty.target didn't
+# actually pull it in.
+Before=getty.target
+
+[Service]
+Environment=TERM=vt100-nav
+m4_ifdef(`TARGET_FEDORA',
+ExecStartPre=-/sbin/securetty %I
+)m4_dnl
+ExecStart=-/sbin/agetty -s %I 115200,38400,9600
+Restart=restart-always
+RestartSec=0
+KillMode=process-group
+
+# Some login implementations ignore SIGTERM, so we send SIGHUP
+# instead, to ensure that login terminates cleanly.
+KillSignal=SIGHUP
diff --git a/units/systemd-auto-console-getty.service.in b/units/systemd-auto-console-getty.service.in
deleted file mode 100644
index 6542cab..0000000
--- a/units/systemd-auto-console-getty.service.in
+++ /dev/null
@@ -1,16 +0,0 @@
-#  This file is part of systemd.
-#
-#  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.
-
-[Unit]
-Description=Automatically Spawn getty on Kernel Console
-
-[Service]
-Type=oneshot
-ExecStart=@rootlibexecdir@/systemd-auto-console-getty
-
-[Install]
-WantedBy=getty.target
diff --git a/units/systemd-auto-serial-getty.service b/units/systemd-auto-serial-getty.service
new file mode 100644
index 0000000..8051c74
--- /dev/null
+++ b/units/systemd-auto-serial-getty.service
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  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.
+
+[Unit]
+Description=Automatically Spawn getty on Serial Kernel Console
+
+[Service]
+Type=oneshot
+ExecStart=@rootlibexecdir@/systemd-auto-serial-getty
+
+[Install]
+WantedBy=getty.target
commit addab137cd8d318e4f543ca56018ee23d51aaca9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 21 03:57:47 2010 +0200

    syslog: add minimal syslog/kmsg bridge syslogd

diff --git a/.gitignore b/.gitignore
index 42d9c8c..1cee1b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-kmsg-syslogd
 systemd-remount-api-vfs
 test-hostname
 systemd-modules-load
diff --git a/Makefile.am b/Makefile.am
index ca25baf..aa2998d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -75,7 +75,8 @@ rootlibexec_PROGRAMS = \
 	systemd-shutdownd \
 	systemd-auto-console-getty \
 	systemd-modules-load \
-	systemd-remount-api-vfs
+	systemd-remount-api-vfs \
+	systemd-kmsg-syslogd
 
 noinst_PROGRAMS = \
 	test-engine \
@@ -143,6 +144,7 @@ dist_systemunit_DATA = \
 	units/systemd-initctl.socket \
 	units/systemd-logger.socket \
 	units/systemd-shutdownd.socket \
+	units/systemd-kmsg-syslogd.socket \
 	units/dev-hugepages.automount \
 	units/dev-hugepages.mount \
 	units/dev-mqueue.automount \
@@ -175,6 +177,7 @@ nodist_systemunit_DATA = \
 	units/systemd-initctl.service \
 	units/systemd-logger.service \
 	units/systemd-shutdownd.service \
+	units/systemd-kmsg-syslogd.service \
 	units/systemd-auto-console-getty.service \
 	units/systemd-modules-load.service \
 	units/systemd-remount-api-vfs.service \
@@ -200,6 +203,7 @@ EXTRA_DIST = \
 	units/systemd-initctl.service.in \
 	units/systemd-logger.service.in \
 	units/systemd-shutdownd.service.in \
+	units/systemd-kmsg-syslogd.service.in \
 	units/systemd-auto-console-getty.service.in \
 	units/systemd-modules-load.service.in \
 	units/systemd-remount-api-vfs.service.in \
@@ -612,6 +616,17 @@ systemd_cgroups_agent_LDADD = \
 	libsystemd-basic.la \
 	$(DBUS_LIBS)
 
+systemd_kmsg_syslogd_SOURCES = \
+	src/kmsg-syslogd.c \
+	src/sd-daemon.c \
+	src/fdset.c
+
+systemd_kmsg_syslogd_CFLAGS = \
+	$(AM_CFLAGS)
+
+systemd_kmsg_syslogd_LDADD = \
+	libsystemd-basic.la
+
 systemctl_SOURCES = \
 	src/systemctl.c \
 	src/utmp-wtmp.c \
diff --git a/src/fdset.c b/src/fdset.c
index b482f0b..29e75a0 100644
--- a/src/fdset.c
+++ b/src/fdset.c
@@ -49,7 +49,7 @@ void fdset_free(FDSet *s) {
                  * here, so that the EBADFD that valgrind will return
                  * us on close() doesn't influence us */
 
-                log_warning("Closing left-over fd %i", PTR_TO_FD(p));
+                /* log_warning("Closing left-over fd %i", PTR_TO_FD(p)); */
                 close_nointr(PTR_TO_FD(p));
         }
 
diff --git a/src/kmsg-syslogd.c b/src/kmsg-syslogd.c
new file mode 100644
index 0000000..f5c8e71
--- /dev/null
+++ b/src/kmsg-syslogd.c
@@ -0,0 +1,545 @@
+/*-*- 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 <sys/socket.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <sys/signalfd.h>
+
+#include "util.h"
+#include "log.h"
+#include "sd-daemon.h"
+#include "fdset.h"
+
+#define SERVER_FD_MAX 16
+#define TIMEOUT ((int) (10*MSEC_PER_SEC))
+
+typedef struct Stream Stream;
+
+typedef struct Server {
+        FDSet *syslog_fds;
+        int kmsg_fd;
+        int epoll_fd;
+        int signal_fd;
+} Server;
+
+static void server_done(Server *s) {
+        assert(s);
+
+        if (s->epoll_fd >= 0)
+                close_nointr_nofail(s->epoll_fd);
+
+        if (s->kmsg_fd >= 0)
+                close_nointr_nofail(s->kmsg_fd);
+
+        if (s->signal_fd >= 0)
+                close_nointr_nofail(s->signal_fd);
+
+        if (s->syslog_fds)
+                fdset_free(s->syslog_fds);
+}
+
+static int server_init(Server *s, unsigned n_sockets) {
+        int r;
+        unsigned i;
+        struct epoll_event ev;
+        sigset_t mask;
+
+        assert(s);
+        assert(n_sockets > 0);
+
+        zero(*s);
+
+        s->kmsg_fd = s->signal_fd = -1;
+
+        if ((s->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
+                r = -errno;
+                log_error("Failed to create epoll object: %s", strerror(errno));
+                goto fail;
+        }
+
+        if (!(s->syslog_fds = fdset_new())) {
+                r = -ENOMEM;
+                log_error("Failed to allocate file descriptor set: %s", strerror(errno));
+                goto fail;
+        }
+
+        for (i = 0; i < n_sockets; i++) {
+                int fd, one = 1;
+
+                fd = SD_LISTEN_FDS_START+i;
+
+                if ((r = sd_is_socket(fd, AF_UNSPEC, SOCK_DGRAM, -1)) < 0) {
+                        log_error("Failed to determine file descriptor type: %s", strerror(-r));
+                        goto fail;
+                }
+
+                if (!r) {
+                        log_error("Wrong file descriptor type.");
+                        r = -EINVAL;
+                        goto fail;
+                }
+
+                if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
+                        log_error("SO_PASSCRED failed: %m");
+
+                zero(ev);
+                ev.events = EPOLLIN;
+                ev.data.fd = fd;
+                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+                        r = -errno;
+                        log_error("Failed to add server fd to epoll object: %s", strerror(errno));
+                        goto fail;
+                }
+
+                if ((r = fdset_put(s->syslog_fds, fd)) < 0) {
+                        log_error("Failed to store file descriptor in set: %s", strerror(-r));
+                        goto fail;
+                }
+        }
+
+        if ((s->kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) {
+                log_error("Failed to open /dev/kmsg for logging: %m");
+                return -errno;
+        }
+
+        assert_se(sigemptyset(&mask) == 0);
+        sigset_add_many(&mask, SIGINT, SIGTERM, -1);
+        assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
+
+        if ((s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
+                log_error("signalfd(): %m");
+                return -errno;
+        }
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.fd = s->signal_fd;
+
+        if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->signal_fd, &ev) < 0) {
+                log_error("epoll_ctl(): %m");
+                return -errno;
+        }
+
+        return 0;
+
+fail:
+        server_done(s);
+        return r;
+}
+
+static int read_priority(const char **buf) {
+        int priority;
+        size_t n;
+        const char *p;
+        int a, b, c;
+
+        assert(buf);
+        assert(*buf);
+
+        p = *buf;
+        n = strlen(p);
+
+        if (n < 3 || p[0] != '<')
+                goto fail;
+
+        if (p[2] == '>') {
+                a = b = 0;
+                c = undecchar(p[1]);
+                p += 3;
+        } else if (n >= 4 && p[3] == '>') {
+                a = 0;
+                b = undecchar(p[1]);
+                c = undecchar(p[2]);
+                p += 4;
+        } else if (n >= 5 && p[4] == '>') {
+                a = undecchar(p[1]);
+                b = undecchar(p[2]);
+                c = undecchar(p[3]);
+                p += 5;
+        } else
+                goto fail;
+
+        if (a < 0 || b < 0 || c < 0)
+                goto fail;
+
+        *buf = p;
+
+        priority = 100*a + 10*b + c;
+        return LOG_PRI(priority);
+
+fail:
+        return LOG_INFO;
+}
+
+static void skip_date(const char **buf) {
+        enum {
+                LETTER,
+                SPACE,
+                NUMBER,
+                SPACE_OR_NUMBER,
+                COLON
+        } sequence[] = {
+                LETTER, LETTER, LETTER,
+                SPACE,
+                SPACE_OR_NUMBER, NUMBER,
+                SPACE,
+                SPACE_OR_NUMBER, NUMBER,
+                COLON,
+                SPACE_OR_NUMBER, NUMBER,
+                COLON,
+                SPACE_OR_NUMBER, NUMBER,
+                SPACE
+        };
+
+        const char *p;
+        unsigned i;
+
+        assert(buf);
+        assert(*buf);
+
+        p = *buf;
+
+        for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
+
+                if (!*p)
+                        return;
+
+                switch (sequence[i]) {
+
+                case SPACE:
+                        if (*p != ' ')
+                                return;
+                        break;
+
+                case SPACE_OR_NUMBER:
+                        if (*p == ' ')
+                                break;
+
+                        /* fall through */
+
+                case NUMBER:
+                        if (*p < '0' || *p > '9')
+                                return;
+
+                        break;
+
+                case LETTER:
+                        if (!(*p >= 'A' && *p <= 'Z') &&
+                            !(*p >= 'a' && *p <= 'z'))
+                                return;
+
+                        break;
+
+                case COLON:
+                        if (*p != ':')
+                                return;
+                        break;
+
+                }
+        }
+
+        *buf = p;
+}
+
+static int read_process(const char **buf, struct iovec *iovec) {
+        const char *p;
+        size_t l;
+
+        assert(buf);
+        assert(*buf);
+        assert(iovec);
+
+        p = *buf;
+
+        p += strspn(p, WHITESPACE);
+        l = strcspn(p, WHITESPACE);
+
+        if (l <= 0 ||
+            p[l-1] != ':')
+                return 0;
+
+        l--;
+
+        if (p[l-1] == ']') {
+                size_t k = l-1;
+
+                for (;;) {
+
+                        if (p[k] == '[') {
+                                l = k;
+                                break;
+                        }
+
+                        if (k == 0)
+                                break;
+
+                        k--;
+                }
+        }
+
+        iovec->iov_base = (char*) p;
+        iovec->iov_len = l;
+        *buf = p + l;
+        return 1;
+}
+
+static void skip_pid(const char **buf) {
+        const char *p;
+
+        assert(buf);
+        assert(*buf);
+
+        p = *buf;
+
+        if (*p != '[')
+                return;
+
+        p++;
+        p += strspn(p, "0123456789");
+
+        if (*p != ']')
+                return;
+
+        p++;
+
+        *buf = p;
+}
+
+static int write_message(Server *s, const char *buf, struct ucred *ucred) {
+        ssize_t k;
+        char priority[4], pid[16];
+        struct iovec iovec[5];
+        unsigned i = 0;
+        char *process = NULL;
+        int r = 0;
+
+        assert(s);
+        assert(buf);
+
+        /* First, set priority field */
+        snprintf(priority, sizeof(priority), "<%i>", read_priority(&buf));
+        char_array_0(priority);
+        IOVEC_SET_STRING(iovec[i++], priority);
+
+        /* Second, skip date */
+        skip_date(&buf);
+
+        /* Then, add process if set */
+        if (read_process(&buf, &iovec[i]) > 0)
+                i++;
+        else if (ucred && get_process_name(ucred->pid, &process) >= 0)
+                IOVEC_SET_STRING(iovec[i++], process);
+
+        /* Skip the stored PID if we have a better one */
+        if (ucred) {
+                snprintf(pid, sizeof(pid), "[%lu]: ", (unsigned long) ucred->pid);
+                char_array_0(pid);
+                IOVEC_SET_STRING(iovec[i++], pid);
+
+                skip_pid(&buf);
+
+                if (*buf == ':')
+                        buf++;
+
+                buf += strspn(buf, WHITESPACE);
+        }
+
+        /* Is the remaining message empty? */
+        if (*buf) {
+
+                /* And the rest is the message */
+                IOVEC_SET_STRING(iovec[i++], buf);
+                IOVEC_SET_STRING(iovec[i++], "\n");
+
+                if ((k = writev(s->kmsg_fd, iovec, i)) <= 0) {
+                        log_error("Failed to write log message to kmsg: %s", k < 0 ? strerror(errno) : "short write");
+                        r = k < 0 ? -errno : -EIO;
+                }
+        }
+
+        free(process);
+
+        return r;
+}
+
+static int process_event(Server *s, struct epoll_event *ev) {
+        assert(s);
+
+        if (ev->events != EPOLLIN) {
+                log_info("Got invalid event from epoll.");
+                return -EIO;
+        }
+
+        if (ev->data.fd == s->signal_fd) {
+                struct signalfd_siginfo sfsi;
+                ssize_t n;
+
+                if ((n = read(s->signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
+
+                        if (n >= 0)
+                                return -EIO;
+
+                        if (errno == EINTR || errno == EAGAIN)
+                                return 0;
+
+                        return -errno;
+                }
+
+                log_debug("Received SIG%s", strna(signal_to_string(sfsi.ssi_signo)));
+                return 0;
+
+        } else {
+                for (;;) {
+                        char buf[LINE_MAX+1];
+                        struct msghdr msghdr;
+                        struct iovec iovec;
+                        struct ucred *ucred;
+                        union {
+                                struct cmsghdr cmsghdr;
+                                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+                        } control;
+                        ssize_t n;
+                        int k;
+                        char *e;
+
+                        zero(iovec);
+                        iovec.iov_base = buf;
+                        iovec.iov_len = sizeof(buf)-1;
+
+                        zero(control);
+                        zero(msghdr);
+                        msghdr.msg_iov = &iovec;
+                        msghdr.msg_iovlen = 1;
+                        msghdr.msg_control = &control;
+                        msghdr.msg_controllen = sizeof(control);
+
+                        if ((n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT)) < 0) {
+
+                                if (errno == EINTR || errno == EAGAIN)
+                                        return 1;
+
+                                log_error("recvmsg() failed: %m");
+                                return -errno;
+                        }
+
+                        if (msghdr.msg_controllen >= CMSG_LEN(sizeof(struct ucred)) &&
+                            control.cmsghdr.cmsg_level == SOL_SOCKET &&
+                            control.cmsghdr.cmsg_type == SCM_CREDENTIALS &&
+                            control.cmsghdr.cmsg_len == CMSG_LEN(sizeof(struct ucred)))
+                                ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
+                        else
+                                ucred = NULL;
+
+                        if ((e = memchr(buf, '\n', n)))
+                                *e = 0;
+                        else
+                                buf[n] = 0;
+
+                        if ((k = write_message(s, strstrip(buf), ucred)) < 0)
+                                return k;
+                }
+        }
+
+        return 1;
+}
+
+int main(int argc, char *argv[]) {
+        Server server;
+        int r = 3, n;
+
+        if (getppid() != 1) {
+                log_error("This program should be invoked by init only.");
+                return 1;
+        }
+
+        if (argc > 1) {
+                log_error("This program does not take arguments.");
+                return 1;
+        }
+
+        log_set_target(LOG_TARGET_KMSG);
+        log_parse_environment();
+        log_open();
+
+        if ((n = sd_listen_fds(true)) < 0) {
+                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
+                return 1;
+        }
+
+        if (n <= 0 || n > SERVER_FD_MAX) {
+                log_error("No or too many file descriptors passed.");
+                return 2;
+        }
+
+        if (server_init(&server, (unsigned) n) < 0)
+                return 3;
+
+        log_debug("systemd-kmsg-syslogd running as pid %lu", (unsigned long) getpid());
+
+        sd_notify(false,
+                  "READY=1\n"
+                  "STATUS=Processing messages...");
+
+        for (;;) {
+                struct epoll_event event;
+                int k;
+
+                if ((k = epoll_wait(server.epoll_fd, &event, 1, TIMEOUT)) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        log_error("epoll_wait() failed: %m");
+                        goto fail;
+                }
+
+                if (k <= 0)
+                        break;
+
+                if ((k = process_event(&server, &event)) < 0)
+                        goto fail;
+
+                if (k == 0)
+                        break;
+        }
+
+        r = 0;
+
+        log_debug("systemd-kmsg-syslogd stopped as pid %lu", (unsigned long) getpid());
+
+fail:
+        sd_notify(false,
+                  "STATUS=Shutting down...");
+
+        server_done(&server);
+
+        return r;
+}
diff --git a/src/log.c b/src/log.c
index 729b9ea..3c42e8e 100644
--- a/src/log.c
+++ b/src/log.c
@@ -32,7 +32,6 @@
 #include "macro.h"
 
 #define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC)
-#define LOG_BUFFER_MAX 1024
 
 static LogTarget log_target = LOG_TARGET_CONSOLE;
 static int log_max_level = LOG_INFO;
@@ -417,7 +416,7 @@ int log_meta(
         const char *func,
         const char *format, ...) {
 
-        char buffer[LOG_BUFFER_MAX];
+        char buffer[LINE_MAX];
         int saved_errno, r;
         va_list ap;
 
@@ -444,7 +443,7 @@ void log_assert(
         const char *func,
         const char *format, ...) {
 
-        static char buffer[LOG_BUFFER_MAX];
+        static char buffer[LINE_MAX];
         int saved_errno = errno;
         va_list ap;
 
diff --git a/src/logger.c b/src/logger.c
index 95d58fc..5a28c21 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -38,7 +38,6 @@
 #include "sd-daemon.h"
 #include "tcpwrap.h"
 
-#define STREAM_BUFFER 2048
 #define STREAMS_MAX 256
 #define SERVER_FD_MAX 16
 #define TIMEOUT ((int) (10*MSEC_PER_SEC))
@@ -85,7 +84,7 @@ struct Stream {
 
         bool prefix;
 
-        char buffer[STREAM_BUFFER];
+        char buffer[LINE_MAX];
         size_t length;
 
         LIST_FIELDS(Stream, stream);
@@ -297,7 +296,7 @@ static int stream_process(Stream *s, usec_t ts) {
         int r;
         assert(s);
 
-        if ((l = read(s->fd, s->buffer+s->length, STREAM_BUFFER-s->length)) < 0) {
+        if ((l = read(s->fd, s->buffer+s->length, LINE_MAX-s->length)) < 0) {
 
                 if (errno == EAGAIN)
                         return 0;
@@ -617,7 +616,7 @@ int main(int argc, char *argv[]) {
 
         r = 0;
 
-        log_info("systemd-logger stopped as pid %lu", (unsigned long) getpid());
+        log_debug("systemd-logger stopped as pid %lu", (unsigned long) getpid());
 
 fail:
         sd_notify(false,
diff --git a/units/.gitignore b/units/.gitignore
index 801e9d6..82a2417 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,4 @@
+systemd-kmsg-syslogd.service
 systemd-modules-load.service
 systemd-remount-api-vfs.service
 systemd-auto-console-getty.service
diff --git a/units/systemd-kmsg-syslogd.service.in b/units/systemd-kmsg-syslogd.service.in
new file mode 100644
index 0000000..e2e0f55
--- /dev/null
+++ b/units/systemd-kmsg-syslogd.service.in
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  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.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=systemd Syslog Kernel Log Buffer Bridge
+DefaultDependencies=no
+
+[Service]
+ExecStart=@rootlibexecdir@/systemd-kmsg-syslogd
+NotifyAccess=all
diff --git a/units/systemd-kmsg-syslogd.socket b/units/systemd-kmsg-syslogd.socket
new file mode 100644
index 0000000..7487cd5
--- /dev/null
+++ b/units/systemd-kmsg-syslogd.socket
@@ -0,0 +1,20 @@
+#  This file is part of systemd.
+#
+#  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.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=Syslog Socket
+DefaultDependencies=no
+Before=sockets.target
+
+[Socket]
+ListenDatagram=/dev/log
+SocketMode=0666
+
+[Install]
+WantedBy=sysinit.target


More information about the systemd-commits mailing list