chiark / gitweb /
logind: make sure there's always a getty available on TTY6
[elogind.git] / src / login / logind.c
index 07755831477e6c3a36287f375a067f7d656e288e..f72eb490fecfe8c3ac6c9b5844b9d6ac4d976971 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->udev_vcsa_fd = -1;
         m->udev_button_fd = -1;
         m->epoll_fd = -1;
+        m->reserve_vt_fd = -1;
 
         m->n_autovts = 6;
 
         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;
         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->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);
         strv_free(m->controllers);
         strv_free(m->reset_controllers);
         strv_free(m->kill_only_users);
@@ -942,30 +947,26 @@ static int vt_is_busy(int vtnr) {
 
 int manager_spawn_autovt(Manager *m, int vtnr) {
         int r;
 
 int manager_spawn_autovt(Manager *m, int vtnr) {
         int r;
-        DBusMessage *message = NULL, *reply = NULL;
         char *name = NULL;
         const char *mode = "fail";
         char *name = NULL;
         const char *mode = "fail";
-        DBusError error;
 
         assert(m);
         assert(vtnr >= 1);
 
 
         assert(m);
         assert(vtnr >= 1);
 
-        dbus_error_init(&error);
-
-        if ((unsigned) vtnr > m->n_autovts)
+        if ((unsigned) vtnr > m->n_autovts &&
+            (unsigned) vtnr != m->reserve_vt)
                 return 0;
 
                 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. */
 
 
-        message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
-        if (!message) {
-                log_error("Could not allocate message.");
-                r = -ENOMEM;
-                goto finish;
+                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) {
         }
 
         if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) {
@@ -974,35 +975,42 @@ int manager_spawn_autovt(Manager *m, int vtnr) {
                 goto finish;
         }
 
                 goto finish;
         }
 
-        if (!dbus_message_append_args(message,
-                                      DBUS_TYPE_STRING, &name,
-                                      DBUS_TYPE_STRING, &mode,
-                                      DBUS_TYPE_INVALID)) {
-                log_error("Could not attach target and flag information to message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
-        if (!reply) {
-                log_error("Failed to start unit: %s", bus_error_message(&error));
-                goto finish;
-        }
-
-        r = 0;
+        r = bus_method_call_with_reply (
+                        m->bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "StartUnit",
+                        NULL,
+                        NULL,
+                        DBUS_TYPE_STRING, &name,
+                        DBUS_TYPE_STRING, &mode,
+                        DBUS_TYPE_INVALID);
 
 finish:
         free(name);
 
 
 finish:
         free(name);
 
-        if (message)
-                dbus_message_unref(message);
+        return r;
+}
+
+static int manager_reserve_vt(Manager *m) {
+        _cleanup_free_ char *p = NULL;
 
 
-        if (reply)
-                dbus_message_unref(reply);
+        assert(m);
 
 
-        dbus_error_free(&error);
+        if (m->reserve_vt <= 0)
+                return 0;
 
 
-        return r;
+        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) {
 }
 
 int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **session) {
@@ -1020,10 +1028,8 @@ int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **sess
         }
 
         p = strdup(cgroup);
         }
 
         p = strdup(cgroup);
-        if (!p) {
-                log_error("Out of memory.");
-                return -ENOMEM;
-        }
+        if (!p)
+                return log_oom();
 
         for (;;) {
                 char *e;
 
         for (;;) {
                 char *e;
@@ -1061,10 +1067,8 @@ int manager_get_user_by_cgroup(Manager *m, const char *cgroup, User **user) {
         }
 
         p = strdup(cgroup);
         }
 
         p = strdup(cgroup);
-        if (!p) {
-                log_error("Out of memory.");
-                return -ENOMEM;
-        }
+        if (!p)
+                return log_oom();
 
         for (;;) {
                 char *e;
 
         for (;;) {
                 char *e;
@@ -1176,8 +1180,7 @@ static int manager_connect_bus(Manager *m) {
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
             !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
             !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
             !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
-                log_error("Not enough memory");
-                r = -ENOMEM;
+                r = log_oom();
                 goto fail;
         }
 
                 goto fail;
         }
 
@@ -1480,6 +1483,9 @@ int manager_startup(Manager *m) {
         /* Remove stale objects before we start them */
         manager_gc(m, false);
 
         /* 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);
         /* And start everything */
         HASHMAP_FOREACH(seat, m->seats, i)
                 seat_start(seat);
@@ -1611,8 +1617,7 @@ int main(int argc, char *argv[]) {
 
         m = manager_new();
         if (!m) {
 
         m = manager_new();
         if (!m) {
-                log_error("Out of memory");
-                r = -ENOMEM;
+                r = log_oom();
                 goto finish;
         }
 
                 goto finish;
         }