chiark / gitweb /
logind: make sure there's always a getty available on TTY6
authorLennart Poettering <lennart@poettering.net>
Mon, 17 Sep 2012 10:39:16 +0000 (12:39 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 17 Sep 2012 10:39:16 +0000 (12:39 +0200)
Previously, if X allocated all 6 TTYs (for multi-session for example) no
getty would be available anymore to guarantee console-based logins.

With the new ReserveVT= switch in logind.conf we can now choose one VT
(6 by default) that will always be subject to autovt-style activation,
i.e. we'll always have a getty on TTY6, and X will never take possession
of it.

TODO
man/logind.conf.xml
src/login/logind-gperf.gperf
src/login/logind.c
src/login/logind.conf
src/login/logind.h

diff --git a/TODO b/TODO
index b3c335e..8c31c74 100644 (file)
--- a/TODO
+++ b/TODO
@@ -55,10 +55,10 @@ F18:
 
 * selinux: merge systemd selinux access controls (dwalsh)
 
-* make logind reserve tty6 or so for text logins, so that gdm never picks it up
-
 Features:
 
+* move cryptsetup key caching into kernel keyctl?
+
 * make nspawn work without terminal
 
 * hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it
index 79a8932..304f570 100644 (file)
 
                                 <listitem><para>Takes a positive
                                 integer. Configures how many virtual
-                                terminals to allocate by default that
-                                -- when switched to --
+                                terminals (VTs) to allocate by default
+                                that -- when switched to and
+                                previously unused --
                                 <literal>autovt</literal> services are
                                 automatically spawned on. These
                                 services are instantiated from the
-                                template
+                                template unit
                                 <filename>autovt@.service</filename>
-                                with the virtual terminal TTY name,
+                                for the respective VT TTY name,
                                 e.g. <filename>autovt@tty4.service</filename>. By
                                 default
                                 <filename>autovt@.service</filename>
                                 <filename>getty@.service</filename>,
                                 i.e. login prompts are started
                                 dynamically as the user switches to
-                                unused virtual terminals. This
-                                parameter hence controls how many
-                                gettys are available on the virtual
-                                terminals. Defaults to 6. When set to
+                                unused virtual terminals. Hence, this
+                                parameter controls how many login
+                                <literal>gettys</literal> are
+                                available on the VTs. If a VT is
+                                already used by some other subsystem
+                                (for example a graphical login) this
+                                kind of activation will not be
+                                attempted. Note that the VT configured
+                                in <varname>ReserveVT=</varname> is
+                                always subject to this kind of
+                                activation, even if it is not one of
+                                VTs configured with the
+                                <varname>NAutoVTs=</varname>
+                                directive. Defaults to 6. When set to
                                 0, automatic spawning of
                                 <literal>autovt</literal> services is
+                                disabled. </para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                                <term><varname>ReserveVT=</varname></term>
+
+                                <listitem><para>Takes a positive
+                                integer. Configures the number of one
+                                virtual terminal that shall
+                                unconditionally be reserved for
+                                <filename>autovt@.service</filename>
+                                activation (see above). The VT
+                                selected with this option will be
+                                marked busy unconditionally so that no
+                                other subsystem will allocate it. This
+                                functionality is useful to ensure that
+                                regardless how many VTs are allocated
+                                by other subsystems one login
+                                <literal>getty</literal> is always
+                                available. Defaults to 6 (with other
+                                words: there'll always be a
+                                <literal>getty</literal> available on
+                                Alt-F6.). When set to 0, VT
+                                reservation is
                                 disabled.</para></listitem>
                         </varlistentry>
 
index 72fdad7..f12718c 100644 (file)
@@ -15,6 +15,7 @@ struct ConfigPerfItem;
 %includes
 %%
 Login.NAutoVTs,          config_parse_unsigned, 0, offsetof(Manager, n_autovts)
+Login.ReserveVT,         config_parse_unsigned, 0, offsetof(Manager, reserve_vt)
 Login.KillUserProcesses, config_parse_bool,     0, offsetof(Manager, kill_user_processes)
 Login.KillOnlyUsers,     config_parse_strv,     0, offsetof(Manager, kill_only_users)
 Login.KillExcludeUsers,  config_parse_strv,     0, offsetof(Manager, kill_exclude_users)
index 229af71..f72eb49 100644 (file)
@@ -50,8 +50,10 @@ Manager *manager_new(void) {
         m->udev_vcsa_fd = -1;
         m->udev_button_fd = -1;
         m->epoll_fd = -1;
+        m->reserve_vt_fd = -1;
 
         m->n_autovts = 6;
+        m->reserve_vt = 6;
         m->inhibit_delay_max = 5 * USEC_PER_SEC;
         m->handle_power_key = HANDLE_NO_SESSION;
         m->handle_sleep_key = HANDLE_TTY_SESSION;
@@ -166,6 +168,9 @@ void manager_free(Manager *m) {
         if (m->epoll_fd >= 0)
                 close_nointr_nofail(m->epoll_fd);
 
+        if (m->reserve_vt_fd >= 0)
+                close_nointr_nofail(m->reserve_vt_fd);
+
         strv_free(m->controllers);
         strv_free(m->reset_controllers);
         strv_free(m->kill_only_users);
@@ -948,20 +953,28 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
         assert(m);
         assert(vtnr >= 1);
 
-        if ((unsigned) vtnr > m->n_autovts)
+        if ((unsigned) vtnr > m->n_autovts &&
+            (unsigned) vtnr != m->reserve_vt)
                 return 0;
 
-        r = vt_is_busy(vtnr);
-        if (r < 0)
-                return r;
-        else if (r > 0)
-                return -EBUSY;
+        if ((unsigned) vtnr != m->reserve_vt) {
+                /* If this is the reserved TTY, we'll start the getty
+                 * on it in any case, but otherwise only if it is not
+                 * busy. */
+
+                r = vt_is_busy(vtnr);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        return -EBUSY;
+        }
 
         if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) {
                 log_error("Could not allocate service name.");
                 r = -ENOMEM;
                 goto finish;
         }
+
         r = bus_method_call_with_reply (
                         m->bus,
                         "org.freedesktop.systemd1",
@@ -980,6 +993,26 @@ finish:
         return r;
 }
 
+static int manager_reserve_vt(Manager *m) {
+        _cleanup_free_ char *p = NULL;
+
+        assert(m);
+
+        if (m->reserve_vt <= 0)
+                return 0;
+
+        if (asprintf(&p, "/dev/tty%u", m->reserve_vt) < 0)
+                return log_oom();
+
+        m->reserve_vt_fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
+        if (m->reserve_vt_fd < 0) {
+                log_warning("Failed to pin reserved VT: %m");
+                return -errno;
+        }
+
+        return 0;
+}
+
 int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **session) {
         Session *s;
         char *p;
@@ -1450,6 +1483,9 @@ int manager_startup(Manager *m) {
         /* Remove stale objects before we start them */
         manager_gc(m, false);
 
+        /* Reserve the special reserved VT */
+        manager_reserve_vt(m);
+
         /* And start everything */
         HASHMAP_FOREACH(seat, m->seats, i)
                 seat_start(seat);
index 78496a0..db5dde4 100644 (file)
@@ -9,6 +9,7 @@
 
 [Login]
 #NAutoVTs=6
+#ReserveVT=6
 #KillUserProcesses=no
 #KillOnlyUsers=
 #KillExcludeUsers=root
index 24d705b..8aa28a3 100644 (file)
@@ -68,6 +68,9 @@ struct Manager {
 
         unsigned n_autovts;
 
+        unsigned reserve_vt;
+        int reserve_vt_fd;
+
         Seat *vtconsole;
 
         char *cgroup_path;