Hi,

Apparently, this bug is a duplicate of 216658, for which a patch was
submitted, then corrected because of 224028/224067/226443/229788/257487,
and then dropped because of 272689.

I hope to have found some correct fix, please see patch. Yes, linux has
been providing VT_GETSTATE since something like 1.0.

Only vt 2-15 can be checked: 1 is always busy, and the size of the mask
is limited. But that should be sufficient for normal use. If somebody
really wants more, he can just set vts by hand.

Please note the O_NOCTTY flag that was missing in my previous patch:
without it you get bug 272689: tty1 would be used as controlling tty...

Now the issue becomes: I run startx & exit on a vt. As expected, login
doesn't come back, but my hard disk becomes full of `/dev/ttyn: already
in use'...

Regards,
Samuel
--- agetty-orig.c       2005-09-05 21:29:39.000000000 +0200
+++ agetty.c    2005-09-05 22:23:00.000000000 +0200
@@ -29,6 +29,7 @@
 #include <utmp.h>
 #include <getopt.h>
 #include <time.h>
+#include <limits.h>
 #include <sys/file.h>
 #include <sys/vt.h>
 #include <linux/tty.h>
@@ -654,96 +655,51 @@ open_tty(tty, tp, local)
        if ((st.st_mode & S_IFMT) != S_IFCHR)
            error(_("/dev/%s: not a character device"), tty);
 
+       (void) close(0);
+       errno = 0;                              /* ignore close(2) errors */
+
        /*
         * Try to avoid opening a vt that is already open, as this will
         * mean that the keyboard will be unusable.
         *
-        * Unfortunately, all the kernel gives us to find out is an ioctl
-        * for the next available vt.  As the kernel doesn't open the vt for
-        * you with the ioctl, there is still a chance of both processes
-        * opening the same vt, but this check is far better than nothing at
-        * all.
-        *
-        * The kernel API sucks, and is unusable for this situation.  What
-        * we really need is an ioctl that says 'does anyone _ELSE_ have
-        * this tty open', and that doesn't exist.  Or better yet, the
-        * kernel really shouldn't allow two processes to have read access
-        * on the same tty at the same time (other than with dup...)  Opens
-        * of the same tty device shouldn't be able to steal reads from
-        * each other.
-        *
-        * Similar to the check added to gdm.
-        *
-        * For now, just turn off this check, restoring the bug that ?dm
-        * (and the system) occasionally get their keyboard locked out by
-        * getty showing up after they've taken a vt that inittab says
-        * goes to a getty.
-        * Bummer.
+        * Only vt 2-15 can be checked because of the size of vt_state.v_state.
         *
+        * As the kernel doesn't open the vt for you with the ioctl, there
+        * is still a chance of both processes opening the same vt, but this
+        * check is far better than nothing at all.
         */
-#if 0
+
        if (strncmp(tty,"tty",3) == 0)
        {
            char *end;
            int vtno;
+           struct vt_stat vtstat;
 
            vtno = strtol(tty+3,&end,10);
-           if (end != tty+3 && *end == '\0' && vtno > 1)
+           if (end != tty+3 && *end == '\0' && vtno > 1
+                           && vtno <= sizeof(vtstat.v_state) * CHAR_BIT)
            {
                int fd;
-               int newvtno;
-               int fds[MAX_NR_CONSOLES];
-               int vt_cnt = 0;
-               int i;
-
-               for ( i = 0 ; i < MAX_NR_CONSOLES ; i++ )
-                   fds[i] = -1;
 
-               if ((fd = open("/dev/tty0", O_WRONLY, 0) ) < 0
+               if ((fd = open("/dev/tty1", O_WRONLY|O_NOCTTY, 0) ) < 0
                    && errno != ENOENT)
-                   error(_("/dev/tty0: cannot open: %m"));
+                   error(_("/dev/tty1: cannot open: %m"));
 
-               if (fd >= 0) do
+               if (fd >= 0)
                {
-                   if ((ioctl(fd, VT_OPENQRY, &newvtno ) < 0))
-                       error(_("failed to query next available vt"));
+                   if ((ioctl(fd, VT_GETSTATE, &vtstat ) < 0))
+                       error(_("failed to query vt %d availability"), vtno);
 
-                   if (newvtno == -1)
-                       error(_("all vts are in use"));
-
-                   if (newvtno > vtno)
+                   if (vtstat.v_state & (1<<vtno))
                        error(_("/dev/%s: already in use"), tty);
 
-                   if (newvtno < vtno)
-                   {
-                       char vtname[TTY_NAME_MAX+3];
-
-                       sprintf( vtname, "tty%d", newvtno );
-
-                       if ((fds[vt_cnt++] =
-                           open(vtname, O_RDWR|O_NONBLOCK, 0)) < 0)
-                       {
-                           error(_("/dev/%s: cannot open: %m"), tty);
-                       }
-                   }
-               } while (newvtno != vtno);
-
-               close(fd);
-               for ( i = 0 ; i < MAX_NR_CONSOLES ; i++ )
-               {
-                   if (fds[i] == -1)
-                       break;
-                   close(fds[i]);
+                   close(fd);
                }
            }
        }
-#endif
 
        /* Open the tty as standard input. */
 
-       (void) close(0);
-       errno = 0;                              /* ignore close(2) errors */
-
        debug(_("open(2)\n"));
        if (open(tty, O_RDWR|O_NONBLOCK, 0) != 0)
            error(_("/dev/%s: cannot open as standard input: %m"), tty);

Reply via email to