summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-09-17 12:39:16 +0200
committerLennart Poettering <lennart@poettering.net>2012-09-17 12:39:16 +0200
commit98a77df5fe8591034c48e5d56d903ee268de37f9 (patch)
treef7e3bed02ed12414e71a0b250710d5b9ab7d080d
parent4db17f291c627c885de668200ff8cce2e57c933f (diff)
logind: make sure there's always a getty available on TTY6
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.
-rw-r--r--TODO4
-rw-r--r--man/logind.conf.xml51
-rw-r--r--src/login/logind-gperf.gperf1
-rw-r--r--src/login/logind.c48
-rw-r--r--src/login/logind.conf1
-rw-r--r--src/login/logind.h3
6 files changed, 92 insertions, 16 deletions
diff --git a/TODO b/TODO
index b3c335ee35..8c31c74571 100644
--- 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
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
index 79a8932cea..304f570b1d 100644
--- a/man/logind.conf.xml
+++ b/man/logind.conf.xml
@@ -71,14 +71,15 @@
<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>
@@ -86,12 +87,46 @@
<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>
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 72fdad739b..f12718cf4e 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -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)
diff --git a/src/login/logind.c b/src/login/logind.c
index 229af714f8..f72eb490fe 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -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);
diff --git a/src/login/logind.conf b/src/login/logind.conf
index 78496a0ef1..db5dde47a0 100644
--- a/src/login/logind.conf
+++ b/src/login/logind.conf
@@ -9,6 +9,7 @@
[Login]
#NAutoVTs=6
+#ReserveVT=6
#KillUserProcesses=no
#KillOnlyUsers=
#KillExcludeUsers=root
diff --git a/src/login/logind.h b/src/login/logind.h
index 24d705b541..8aa28a322c 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -68,6 +68,9 @@ struct Manager {
unsigned n_autovts;
+ unsigned reserve_vt;
+ int reserve_vt_fd;
+
Seat *vtconsole;
char *cgroup_path;