diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c index 39def47..03488fd 100644 --- a/daemon/gdm-server.c +++ b/daemon/gdm-server.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #ifdef HAVE_SYS_PRCTL_H #include @@ -154,6 +158,92 @@ _gdm_server_query_ck_for_display_device (GdmServer *server) return out; } +#ifndef O_NOCTTY +# define O_NOCTTY 0 +#endif + +static int +open_vt (int vtno) +{ + char *vtname; + int fd; + + vtname = g_strdup_printf ("/dev/tty%d", vtno); + + do { + errno = 0; + fd = open (vtname, O_RDWR | O_NOCTTY, 0); + } while (errno == EINTR); + + g_free (vtname); + return fd; +} + +static gint +find_first_probably_free_vt (void) +{ + int fd, fdv; + int vtno; + unsigned short vtmask; + struct vt_stat vtstat; + guint v_state; + + fdv = -1; + + do { + errno = 0; + fd = open ("/dev/console", O_WRONLY | O_NOCTTY, 0); + } while (errno == EINTR); + + if (fd >= 0) { + if (ioctl (fd, VT_GETSTATE, &vtstat) >= 0) { + v_state = vtstat.v_state; + } else { + close (fd); + v_state = 0; + fd = -1; + } + } else { + v_state = 0; + } + + if (fd < 0) { + do { + errno = 0; + fd = open ("/dev/console", O_RDONLY | O_NOCTTY, 0); + } while (errno == EINTR); + + if (fd >= 0) { + if (ioctl (fd, VT_GETSTATE, &vtstat) >= 0) + v_state = vtstat.v_state; + } + } + + for (vtno = 7, vtmask = 1 << vtno; vtmask; vtno++, vtmask <<= 1) { + /* Is this console in use? */ + if (v_state & vtmask) + continue; + + /* No, try to open it */ + fdv = open_vt (vtno); + if (fdv >= 0) + break; + + /* If we're here, kernel indicated that the console was free, + * but we failed to open it. Just go on to higher VTs. */ + } + + if (fdv >= 0) + close (fdv); + else + vtno = -1; + + if (fd >= 0) + close (fd); + + return vtno; +} + char * gdm_server_get_display_device (GdmServer *server) { @@ -314,6 +402,11 @@ gdm_server_resolve_command_line (GdmServer *server, if (vtarg != NULL && ! gotvtarg) { argv[len++] = g_strdup (vtarg); + } else if (!query_in_arglist && !gotvtarg) { + gint vtnum = find_first_probably_free_vt (); + + if (vtnum > 0) + argv [len++] = g_strdup_printf ("vt%d", vtnum); } argv[len++] = NULL;