[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#484366: Bug#493865: cttyhack does not handle other serial devices than ttySn (was: Bug booting from console)



On Fri, Aug 15, 2008 at 10:55:34PM +0200, Jérémy Bobbio wrote:
> On Sat, Aug 09, 2008 at 06:19:09PM +0200, Frans Pop wrote:
> > On Wednesday 06 August 2008, Jérémy Bobbio wrote:
> > I think someone should look into the option of starting udevd _before_ we 
> > run init (as also suggested by Marco in a recent discussion on IRC).
> 
> Attached is a patch the implements this.  Details inside.
> 
> Attached is also a patch against udev that simple moves
> /lib/debian-installer-startup.d/S02udev to
> /lib/debian-installer/start-udev so the script can be called from the
> init script.

Ok, I have spent more time working on this and I think that there might
be a good chance that this would be the last time.

Bastian Blank suggested on IRC when we discussed the proposed fix
against busybox (see #493865) to replace cttyhack with a custom
solution.

I have digged the kernel source code, made several false starts, but the
attached patch contain a solution that should work in any cases.  It is
based on the previous patch that make udev starts earlier.

More details inside.  Please have a look, I have quite some faith in
this approach.

Cheers,
-- 
Jérémy Bobbio                        .''`. 
lunar@debian.org                    : :Ⓐ  :  # apt-get install anarchism
                                    `. `'` 
                                      `-   
commit 02f46f59a160ced45df3b9bcc9ce54175627e6b8
Author: Jérémy Bobbio <lunar@debian.org>
Date:   Sat Aug 23 20:59:30 2008 +0200

    Rework the switch from /dev/console to the real console device
    
    As cttyhack is not compatible with console devices other than ttySx,
    let's replace replace it with a custom solution.
    
    A new shell sript is introduced in rootskel, /sbin/reopen-console.
    As there is no proper way to retrieve the "selected console" from the
    kernel, this script tries to redo the kernel logic internally by doing
    the following:
     1. Parse kernel messages to find which consoles have been enabled.
     2. If there is only one console, use it.
        If there is a "handover" message, use the "real" console.
     3. Parse the kernel command-line to find the last "console=" option
        that matches one of the enabled console.
     4. If nothing was found, default to /dev/console as a safety net.
    
    This script then exec() a small binary, /sbin/steal-ctty, that will open
    the device found, mangle the file descriptors and claim the ctty.  Once
    done, another exec() will finally execute the arguments given to
    /bin/reopen-console.
    
    cttyhack was previously used in /etc/inittab for both
    /sbin/debian-installer-startup and /sbin/debian-installer. To get rid of
    this small redundancy, reopen-console is called directly in /init.
    
    As this process now uses far more file descriptors, the previous numbers
    assigned for extra file descriptors in cdebconf was reached when
    starting graphical installations.  These have been increased in order to
    solve that issue.
    
    (Closes: #484366)

diff --git a/packages/cdebconf/debian/changelog b/packages/cdebconf/debian/changelog
index 9574a68..09e1ad8 100644
--- a/packages/cdebconf/debian/changelog
+++ b/packages/cdebconf/debian/changelog
@@ -7,6 +7,9 @@ cdebconf (0.134) UNRELEASED; urgency=low
     (Closes: #487691)
   * Use a dynamically allocated rope in strexpand().
     (Closes: #496093)
+  * Increase extra fd numbers by 30 in confmodule_run().
+    This is necessary as the new method of switching from /dev/console to the
+    real device open more file descriptors in the process space.
 
   [ Colin Watson ]
   * When receiving a new template with DATA, ensure that the corresponding
diff --git a/packages/cdebconf/src/confmodule.c b/packages/cdebconf/src/confmodule.c
index 66eb13c..19f89c3 100644
--- a/packages/cdebconf/src/confmodule.c
+++ b/packages/cdebconf/src/confmodule.c
@@ -181,15 +181,15 @@ static pid_t confmodule_run(struct confmodule *mod, int argc, char **argv)
             DIE("Cannot execute client config script");
             break;
         case 0:
-            /* 20=read/to, 21=write/to, 22=read/from, 23=write/from, 24=null */
+            /* 50=read/to, 51=write/to, 52=read/from, 53=write/from, 54=null */
             config[4] = open("/dev/null", O_RDWR);
             for (i = 0; i < 5; i++)
-                check_fd(config[i], 20 + i, old);
+                check_fd(config[i], 50 + i, old);
             for (i = 0; i <= 2; i++)
-                dup2(old[i] ? i : 24, DEBCONF_OLD_FD_BASE + i);
-            dup2(20, 0); dup2(23, 1); dup2(23, 3);
+                dup2(old[i] ? i : 54, DEBCONF_OLD_FD_BASE + i);
+            dup2(50, 0); dup2(53, 1); dup2(53, 3);
             for (i = 0; i < 5; i++)
-                close(20 + i);
+                close(50 + i);
 
             args = (char **)malloc(sizeof(char *) * argc);
             for (i = 1; i < argc; i++)
diff --git a/packages/rootskel/debian/changelog b/packages/rootskel/debian/changelog
index 32532c2..838411f 100644
--- a/packages/rootskel/debian/changelog
+++ b/packages/rootskel/debian/changelog
@@ -12,6 +12,9 @@ rootskel (1.65) UNRELEASED; urgency=low
   [ Jérémy Bobbio ]
   * Start udev before running init.
     Depends: udev-udeb (>= 0.125-6)
+  * Rework the switch from /dev/console to the real console device
+    (e.g.  /dev/tty0).  (Closes: #484366)
+    Breaks: cdebconf-gtk-udeb (<< 0.134)
 
  -- Colin Watson <cjwatson@debian.org>  Tue, 29 Jul 2008 17:24:58 +0100
 
diff --git a/packages/rootskel/src/etc/inittab b/packages/rootskel/src/etc/inittab
index 8aef38f..a2a2421 100644
--- a/packages/rootskel/src/etc/inittab
+++ b/packages/rootskel/src/etc/inittab
@@ -2,10 +2,10 @@
 # busybox init configuration for debian-installer
 
 # main rc script
-::sysinit:/bin/cttyhack /sbin/debian-installer-startup
+::sysinit:/sbin/debian-installer-startup
 
 # main setup program
-::respawn:/bin/cttyhack /sbin/debian-installer
+::respawn:/sbin/debian-installer
 
 # convenience shells
 tty2::askfirst:-/bin/sh
diff --git a/packages/rootskel/src/init b/packages/rootskel/src/init
index 0a05b25..c8567b4 100755
--- a/packages/rootskel/src/init
+++ b/packages/rootskel/src/init
@@ -8,7 +8,7 @@ mount /proc
 mount /sys
 /lib/debian-installer/start-udev
 
-init='busybox init'
+init='/bin/busybox init'
 for i in $(cat /proc/cmdline); do
 	case $i in
 		init=*)
@@ -17,4 +17,4 @@ for i in $(cat /proc/cmdline); do
 	esac
 done
 debugshell "before init"
-exec $init
+exec /sbin/reopen-console $init
diff --git a/packages/rootskel/src/sbin/Makefile b/packages/rootskel/src/sbin/Makefile
index d6c072e..b5e374e 100644
--- a/packages/rootskel/src/sbin/Makefile
+++ b/packages/rootskel/src/sbin/Makefile
@@ -4,6 +4,16 @@ files_exec = \
 	debian-installer \
 	debian-installer-startup \
 	shutdown \
-	init
+	init \
+	reopen-console \
+	steal-ctty
+
+steal-ctty: steal-ctty.c
+	gcc -Os -Wall steal-ctty.c -o steal-ctty
+
+build: steal-ctty
+
+clean:
+	rm -f steal-ctty
 
 include ../../Makefile.inc
diff --git a/packages/rootskel/src/sbin/reopen-console b/packages/rootskel/src/sbin/reopen-console
new file mode 100644
index 0000000..b4bbe81
--- /dev/null
+++ b/packages/rootskel/src/sbin/reopen-console
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+# In order to give proper access to the tty, we need to locate the device
+# corresponding to the console we are actually using.
+
+# If the kernel emitted an "handover" message, then it's the one
+console="$(dmesg -s 65535 |
+	sed -n -e 's/.*\] console handover: boot \[.*\] -> real \[\(.*\)\]$/\1/p')"
+
+if [ -z "$console" ]; then
+	# Retrieve all enabled consoles from boot log
+	consoles="$(dmesg -s 65535 |
+		sed -n -e 's/.*\] console \[\(.*\)\] enabled/\1/p')"
+	# Only one console? Then we are good.
+	if [ $(echo "$consoles" | wc -l) -eq 1 ]; then
+		console="$consoles"
+	fi
+fi
+
+if [ -z "$console" ]; then
+	# Locate the last enabled console present on the command line
+	for arg in $(cat /proc/cmdline); do
+		case $arg in
+		    console=*)
+			arg=${arg#console=}
+			if echo "$consoles" | grep -q "^${arg%%,*}$"; then
+				console=${arg%%,*}
+			fi
+			;;
+		esac
+	done
+fi
+
+if [ -z "$console" ]; then
+	# Still nothing? Default to /dev/console for safety
+	console=console
+fi
+
+# Some other session may have it as ctty. Steal it from them
+exec /sbin/steal-ctty /dev/$console "$@"
diff --git a/packages/rootskel/src/sbin/steal-ctty.c b/packages/rootskel/src/sbin/steal-ctty.c
new file mode 100644
index 0000000..93ad3bc
--- /dev/null
+++ b/packages/rootskel/src/sbin/steal-ctty.c
@@ -0,0 +1,25 @@
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int main(int argc, char ** argv)
+{
+    int fd;
+
+    if (-1 == (fd = open(argv[1], O_RDWR))) {
+        perror("steal-ctty");
+        return 1;
+    }
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    while (fd > 2) {
+        close(fd--);
+    }
+    ioctl(0, TIOCSCTTY, (char *) 1);
+    execvp(argv[2], &argv[2]);
+    /* never reached. */
+    return 0;
+}

Attachment: signature.asc
Description: Digital signature


Reply to: