cttyhack: check sysfs for the name of the active console
authorKevin Cernekee <cernekee@gmail.com>
Wed, 13 Jul 2011 07:26:58 +0000 (09:26 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 13 Jul 2011 07:26:58 +0000 (09:26 +0200)
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/cttyhack.c

index d1ac2cd..522a1ba 100644 (file)
 //config:      bool "cttyhack"
 //config:      default y
 //config:      help
-//config:        One common problem reported on the mailing list is "can't access tty;
-//config:        job control turned off" error message which typically appears when
-//config:        one tries to use shell with stdin/stdout opened to /dev/console.
+//config:        One common problem reported on the mailing list is the "can't
+//config:        access tty; job control turned off" error message, which typically
+//config:        appears when one tries to use a shell with stdin/stdout on
+//config:        /dev/console.
 //config:        This device is special - it cannot be a controlling tty.
 //config:
-//config:        Proper solution is to use correct device instead of /dev/console.
+//config:        The proper solution is to use the correct device instead of
+//config:        /dev/console.
 //config:
-//config:        cttyhack provides "quick and dirty" solution to this problem.
+//config:        cttyhack provides "quick and dirty" solution to this problem.
 //config:        It analyzes stdin with various ioctls, trying to determine whether
 //config:        it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line).
-//config:        If it detects one, it closes stdin/out/err and reopens that device.
-//config:        Then it executes given program. Opening the device will make
+//config:        On Linux it also checks sysfs for a pointer to the active console.
+//config:        If cttyhack is able to find the real console device, it closes
+//config:        stdin/out/err and reopens that device.
+//config:        Then it executes the given program. Opening the device will make
 //config:        that device a controlling tty. This may require cttyhack
 //config:        to be a session leader.
 //config:
@@ -115,33 +119,46 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv)
                close(fd);
        } else {
                /* We don't have ctty (or don't have "/dev/tty" node...) */
-               if (0) {}
-#ifdef TIOCGSERIAL
-               else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) {
-                       /* this is a serial console */
-                       sprintf(console + 8, "S%d", u.sr.line);
-               }
-#endif
+               do {
 #ifdef __linux__
-               else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) {
-                       /* this is linux virtual tty */
-                       sprintf(console + 8, "S%d" + 1, u.vt.v_active);
-               }
+                       int s = open_read_close("/sys/class/tty/console/active",
+                               console + 5, sizeof(console) - 5 - 1);
+                       if (s > 0) {
+                               /* found active console via sysfs (Linux 2.6.38+) */
+                               console[5 + s] = '\0';
+                               break;
+                       }
+
+                       if (ioctl(0, VT_GETSTATE, &u.vt) == 0) {
+                               /* this is linux virtual tty */
+                               sprintf(console + 8, "S%d" + 1, u.vt.v_active);
+                               break;
+                       }
 #endif
-               if (console[8]) {
-                       fd = xopen(console, O_RDWR);
-                       //bb_error_msg("switching to '%s'", console);
-                       dup2(fd, 0);
-                       dup2(fd, 1);
-                       dup2(fd, 2);
-                       while (fd > 2)
-                               close(fd--);
-                       /* Some other session may have it as ctty,
-                        * steal it from them:
-                        */
-                       ioctl(0, TIOCSCTTY, 1);
-               }
+#ifdef TIOCGSERIAL
+                       if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) {
+                               /* this is a serial console, asuming it is named /dev/ttySn */
+                               sprintf(console + 8, "S%d", u.sr.line);
+                               break;
+                       }
+#endif
+                       /* nope, could not find it */
+                       goto ret;
+               } while (0);
+
+               fd = xopen(console, O_RDWR);
+               //bb_error_msg("switching to '%s'", console);
+               dup2(fd, 0);
+               dup2(fd, 1);
+               dup2(fd, 2);
+               while (fd > 2)
+                       close(fd--);
+               /* Some other session may have it as ctty,
+                * steal it from them:
+                */
+               ioctl(0, TIOCSCTTY, 1);
        }
 
+ret:
        BB_EXECVP_or_die(argv);
 }