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

Re: Multiple console support in d-i



On 2019-02-21 00:55 +0000, Steve McIntyre wrote:
> Hey Wookey,
> 
> Reviewing the code from your patches in sequence, I think the approach
> looks good *except* I think you've missed a patch or a commit or
> something.
> 
> Trying to apply debian-installer-multiple-consoles.patch and
> rootskel-multiple-consoles-inittab.patch in sequence, there are patch
> failures. They clearly depend in that order for the changes in
> src/etc/inittab-linux, but the src/sbin/reopen-console-linux hunks
> don't match up. The last thing I want to do here is miss a line in the
> middle of fixing up by hand and break this... :-)
> 
> Could you post a single patch against current HEAD with all of your
> changes rolled up please?

Well, there are two branches. The original implmentation and the 'use init' implementation.
So attached are two independent (i.e. each is against rootskel HEAD) for those.
Original: rootskel-multiple-consoles2.patch
Init-based: rootskel-multiple-consoles-inittab3.patch

Use one or the other, not both.

The finish-install patch has to be separate because it's a different git repo. Also included.
Required in either case.

Wookey
-- 
Principal hats:  Linaro, Debian, Wookware, ARM
http://wookware.org/
diff --git a/src/etc/inittab-linux b/src/etc/inittab-linux
index a7b8a23..437e208 100644
--- a/src/etc/inittab-linux
+++ b/src/etc/inittab-linux
@@ -5,7 +5,7 @@
 ::sysinit:/sbin/reopen-console /sbin/debian-installer-startup
 
 # main setup program
-::respawn:/sbin/reopen-console /sbin/debian-installer
+::respawn:/sbin/reopen-console --all-consoles /sbin/debian-installer
 
 # convenience shells
 tty2::askfirst:-/bin/sh
diff --git a/src/sbin/reopen-console-linux b/src/sbin/reopen-console-linux
index 3287dd0..e13bfa3 100755
--- a/src/sbin/reopen-console-linux
+++ b/src/sbin/reopen-console-linux
@@ -1,74 +1,68 @@
 #!/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.
+# corresponding to each console we are actually using.
+
+# This script is run twice, once at sysinit to run the debian-installer-startup
+# rc scripts, and once to start the installer itself.
+# The first time it parses the consoles used, the second time they are read from files
+# The startup scripts need to be run just once (on one console) (not idempotent)
+# The installer is run on all the enabled consoles (using the --all-consoles option)
+
 
 NL="
 "
 
-console=
-if ! [ -f /var/run/console-device ]; then
-	# If the kernel emitted a "handover" message, then it's the one
-	case $(uname -r) in
-	    2.6.2*|2.6.3[01]*)
-		console="$(dmesg -s 262143 |
-			sed -n -r -e 's/(.*\])? *console handover: boot \[.*\] -> real \[(.*)\]$/\2/p')"
-		;;
-	    2.6.3[234567]*)
-		console="$(dmesg -s 262143 |
-			sed -n -r -e 's/(.*\])? *console \[(.*)\] enabled, bootconsole disabled$/\2/p')"
-		;;
-	    *) # >= 2.6.38
-		console_major_minor="$(get-real-console-linux)"
-		console_raw="$(readlink "/sys/dev/char/${console_major_minor}")"
-		console="${console_raw##*/}"
-		;;
-	esac
-
-	# Except if it is the wrong type...
-	if [ "$console" ] && [ "$(console-type)" = serial ] && \
-	   expr "$console" : "tty[0-9]" >/dev/null; then
-		console=
-	fi
+if ! [ -f /var/run/console-devices ]; then
 
 	consoles=
-	if [ -z "$console" ]; then
-		# Retrieve all enabled consoles from boot log; ignore those
-		# for which no device file exists
-		for cons in $(dmesg -s 262143 |
-			sed -n -r -e 's/(.*\])? *console \[(.*)\] enabled/\2/p')
-		do
-			if [ -e "/dev/$cons" ]; then
-				consoles="${consoles:+$consoles$NL}$cons"
-			fi
-		done
-		# Only one console? Then we are good.
-		if [ $(echo "$consoles" | wc -l) -eq 1 ]; then
-			console="$consoles"
+	preferred=
+	# Retrieve all enabled consoles from kernel; ignore those
+	# for which no device file exists
+
+	kernelconsoles="$(cat /proc/consoles)"
+	for cons in $(echo "$kernelconsoles" | sed -n -r -e 's/(^.*)  .*\((.*)\).*$/\1/p' )
+	do
+		status=$(echo "$kernelconsoles" | grep $cons | sed -n -r -e 's/(^.*) *.*\((.*)\).*$/\2/p' )
+		if [ -e "/dev/$cons" ] && [ $(echo "$status" | grep -o 'E') ]; then
+			consoles="${consoles:+$consoles$NL}$cons"
 		fi
-	fi
+		# 'C' console is 'most prefered'.
+		if [ $(echo "$status" | grep -o 'C') ]; then
+			preferred="$cons"
+		fi
+	done
 
-	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=}
-				cons=${arg%%,*}
-				if echo "$consoles" | grep -q "^$cons$"; then
-					console=$cons
-				fi
-				;;
-			esac
-		done
+	if [ -z "$consoles" ]; then
+		# Nothing found? Default to /dev/console.
+		consoles=console
 	fi
-
-	if [ -z "$console" ]; then
-		# Still nothing? Default to /dev/console.
-		console=console
+	if [ -z "$preferred" ]; then
+		#None marked preferred? Use the first one
+		preferred=$(echo "$consoles" | head -n 1) 
 	fi
-	echo /dev/$console > /var/run/console-device
+	
+	for cons in $consoles
+	do
+		echo "/dev/$cons " >> /var/run/console-devices
+	done
+	echo "/dev/$preferred " > /var/run/console-preferred
 fi
 
-# Some other session may have it as ctty. Steal it from them
-exec /sbin/steal-ctty $(cat /var/run/console-device) "$@"
+# run startup scripts on one console, D-I itself on all consoles
+if [ "$1"x = "--all-consoles"x ]; then
+	shift
+	# Start d-i on each console.
+	for cons in $(cat /var/run/console-devices)
+	do
+		/sbin/steal-ctty $cons "$@" &
+	done
+	#Don't respawn in init if running installer on multiple consoles
+	sleep 2147483647  #'infinity' not supported in D-I busybox; 68 years will have to do
+else
+	cons=$(cat /var/run/console-preferred)
+	# Some other session may have console as ctty. Steal it from them
+	exec /sbin/steal-ctty $cons "$@"
+fi
+
+
diff --git a/src/sbin/steal-ctty.c b/src/sbin/steal-ctty.c
index 0f3b14f..b99c1bb 100644
--- a/src/sbin/steal-ctty.c
+++ b/src/sbin/steal-ctty.c
@@ -28,8 +28,14 @@ int main(int argc, char ** argv)
     while (fd > 2) {
         close(fd--);
     }
-    ioctl(0, TIOCSCTTY, (char *) 1);
-    execvp(argv[2], &argv[2]);
+    /* make controlling tty if possible - can't be done if D-I is 
+       run on multiple consoles so just quietly move on */
+    if (-1 == ioctl(0, TIOCSCTTY, (char *) 1)) {
+      }
+    if (-1 == execvp(argv[2], &argv[2])) {
+        perror("execvp");
+        return 1;
+    }
     /* never reached. */
     return 0;
 }
diff --git a/src/etc/inittab-linux b/src/etc/inittab-linux
index a7b8a23..830ee94 100644
--- a/src/etc/inittab-linux
+++ b/src/etc/inittab-linux
@@ -5,7 +5,6 @@
 ::sysinit:/sbin/reopen-console /sbin/debian-installer-startup
 
 # main setup program
-::respawn:/sbin/reopen-console /sbin/debian-installer
 
 # convenience shells
 tty2::askfirst:-/bin/sh
diff --git a/src/sbin/reopen-console-linux b/src/sbin/reopen-console-linux
index 3287dd0..bd734ff 100755
--- a/src/sbin/reopen-console-linux
+++ b/src/sbin/reopen-console-linux
@@ -1,74 +1,67 @@
 #!/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.
+# First find the enabled consoles from the kernel, noting if one is 'preferred'
+# Record these.
+# Run the startup scripts on the preferred console
+
+# In order to have D-I appear on all consoles, edit the inittab to add one entry
+# for each console, running debian-installer.
+# Finally HUP init so that it runs those installers
+# (but doesn't rerun the sysinit startup stuff, including this script) 
+
 
 NL="
 "
 
-console=
-if ! [ -f /var/run/console-device ]; then
-	# If the kernel emitted a "handover" message, then it's the one
-	case $(uname -r) in
-	    2.6.2*|2.6.3[01]*)
-		console="$(dmesg -s 262143 |
-			sed -n -r -e 's/(.*\])? *console handover: boot \[.*\] -> real \[(.*)\]$/\2/p')"
-		;;
-	    2.6.3[234567]*)
-		console="$(dmesg -s 262143 |
-			sed -n -r -e 's/(.*\])? *console \[(.*)\] enabled, bootconsole disabled$/\2/p')"
-		;;
-	    *) # >= 2.6.38
-		console_major_minor="$(get-real-console-linux)"
-		console_raw="$(readlink "/sys/dev/char/${console_major_minor}")"
-		console="${console_raw##*/}"
-		;;
-	esac
-
-	# Except if it is the wrong type...
-	if [ "$console" ] && [ "$(console-type)" = serial ] && \
-	   expr "$console" : "tty[0-9]" >/dev/null; then
-		console=
-	fi
+consoles=
+preferred=
+# Retrieve all enabled consoles from kernel; ignore those
+# for which no device file exists
 
-	consoles=
-	if [ -z "$console" ]; then
-		# Retrieve all enabled consoles from boot log; ignore those
-		# for which no device file exists
-		for cons in $(dmesg -s 262143 |
-			sed -n -r -e 's/(.*\])? *console \[(.*)\] enabled/\2/p')
-		do
-			if [ -e "/dev/$cons" ]; then
-				consoles="${consoles:+$consoles$NL}$cons"
-			fi
-		done
-		# Only one console? Then we are good.
-		if [ $(echo "$consoles" | wc -l) -eq 1 ]; then
-			console="$consoles"
-		fi
+kernelconsoles="$(cat /proc/consoles)"
+for cons in $(echo "$kernelconsoles" | sed -n -r -e 's/(^.*)  .*\((.*)\).*$/\1/p' )
+do
+	status=$(echo "$kernelconsoles" | grep $cons | sed -n -r -e 's/(^.*) *.*\((.*)\).*$/\2/p' )
+	if [ -e "/dev/$cons" ] && [ $(echo "$status" | grep -o 'E') ]; then
+		consoles="${consoles:+$consoles$NL}$cons"
 	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=}
-				cons=${arg%%,*}
-				if echo "$consoles" | grep -q "^$cons$"; then
-					console=$cons
-				fi
-				;;
-			esac
-		done
+	# 'C' console is 'most prefered'.
+	if [ $(echo "$status" | grep -o 'C') ]; then
+		preferred="$cons"
 	fi
+done
 
-	if [ -z "$console" ]; then
-		# Still nothing? Default to /dev/console.
-		console=console
-	fi
-	echo /dev/$console > /var/run/console-device
+if [ -z "$consoles" ]; then
+	# Nothing found? Default to /dev/console.
+	consoles=console
 fi
+if [ -z "$preferred" ]; then
+	#None marked preferred? Use the first one
+	preferred=$(echo "$consoles" | head -n 1) 
+fi
+
+for cons in $consoles
+do
+	echo "/dev/$cons " >> /var/run/console-devices
+done
+echo "/dev/$preferred " > /var/run/console-preferred
+
+
+#Add debian-installer lines into inittab - one per console
+inittab=
+for cons in $(cat /var/run/console-devices)
+do
+	DIline="${cons#/dev/}::respawn:/sbin/debian-installer"
+	inittab="${inittab:+$inittab$NL}$DIline"
+done
+
+echo "$inittab" > /tmp/initlines
+sed -i -e '/# main setup program/r /tmp/initlines' /etc/inittab
+
+#Run the startup scripts
+cons=$(cat /var/run/console-preferred)
+# Some other session may have console as ctty. Steal it from them
+/sbin/steal-ctty $cons "$@"  
 
-# Some other session may have it as ctty. Steal it from them
-exec /sbin/steal-ctty $(cat /var/run/console-device) "$@"
+#Finally restart init to run debian-installer on discovered consoles
+kill -HUP 1
diff --git a/src/sbin/steal-ctty.c b/src/sbin/steal-ctty.c
index 0f3b14f..b99c1bb 100644
--- a/src/sbin/steal-ctty.c
+++ b/src/sbin/steal-ctty.c
@@ -28,8 +28,14 @@ int main(int argc, char ** argv)
     while (fd > 2) {
         close(fd--);
     }
-    ioctl(0, TIOCSCTTY, (char *) 1);
-    execvp(argv[2], &argv[2]);
+    /* make controlling tty if possible - can't be done if D-I is 
+       run on multiple consoles so just quietly move on */
+    if (-1 == ioctl(0, TIOCSCTTY, (char *) 1)) {
+      }
+    if (-1 == execvp(argv[2], &argv[2])) {
+        perror("execvp");
+        return 1;
+    }
     /* never reached. */
     return 0;
 }
commit 2e238ab985eebd44f29cc7b5cd6b7cacc71d792e
Author: Wookey <wookey@wookware.org>
Date:   Fri Feb 15 01:50:44 2019 +0000

    Update to deal with multiple consoles

diff --git a/finish-install.d/90console b/finish-install.d/90console
index bd2f528..0045046 100755
--- a/finish-install.d/90console
+++ b/finish-install.d/90console
@@ -38,72 +38,76 @@ case "$(udpkg --print-os)" in
 	hurd)
                 # TODO: detect VGA hurd console, and enable it in installed
                 # system.
-		console=console
+		consoles=/dev/console
 		;;
 	*)
-		console=$(cat /var/run/console-device)
-		console=${console#/dev/}
+		consoles=$(cat /var/run/console-devices)
 		;;
 esac
 
-if [ -f /target/etc/init/tty1.conf ]; then
-	upstart_tty1=/target/etc/init/tty1.conf
-	upstart_console () {
+for console in $consoles
+do
+	console=${console#/dev/}
+
+	if [ -f /target/etc/init/tty1.conf ]; then
+	    upstart_tty1=/target/etc/init/tty1.conf
+	    upstart_console () {
 		echo "/target/etc/init/$1.conf"
-	}
-elif [ -f /target/etc/event.d/tty1 ]; then
-	upstart_tty1=/target/etc/event.d/tty1
-	upstart_console () {
+	    }
+	elif [ -f /target/etc/event.d/tty1 ]; then
+	    upstart_tty1=/target/etc/event.d/tty1
+	    upstart_console () {
 		echo "/target/etc/event.d/$1"
-	}
-else
-	upstart_tty1=
-fi
-
-case "$console" in
-    tty[A-Zu]*|duart*)
-	log "Configuring init for serial console"
-	consoletype=${console%%[0-9]*}
-	ttyline=${console#$consoletype}
-	ttyspeed=$(chroot /target stty --file /dev/$console speed)
-	ttyterm="$TERM"
-
-	flowctrlarg=""
-	if uses_hw_flowcontrol $console; then
-		flowctrlarg="-h "
+	    }
+	else
+	    upstart_tty1=
 	fi
 
-	if [ -z "$ttyterm" ]; then ttyterm=vt100; fi
-	if [ -z "$ttyspeed" ]; then ttyspeed=9600; fi
+	case "$console" in
+	    tty[A-Zu]*|duart*)
+		log "Configuring init for serial console"
+		consoletype=${console%%[0-9]*}
+		ttyline=${console#$consoletype}
+		ttyspeed=$(chroot /target stty --file /dev/$console speed)
+		ttyterm="$TERM"
+
+		flowctrlarg=""
+		if uses_hw_flowcontrol $console; then
+		    flowctrlarg="-h "
+		fi
 
-	if [ -f /target/etc/inittab ]; then
-		# Disable regular VTs
-		if [ -z "$KEEP_VT" ]; then
+		if [ -z "$ttyterm" ]; then ttyterm=vt100; fi
+		if [ -z "$ttyspeed" ]; then ttyspeed=9600; fi
+
+		if [ -f /target/etc/inittab ]; then
+		    # Disable regular VTs
+		    if [ -z "$KEEP_VT" ]; then
 			sed -i -e "s/^\([1-6]\):/#\1:/" /target/etc/inittab
+		    fi
+		    # Enable serial console
+		    sed -i -e "s/^#T0\(.*\)ttyS.*/T$ttyline\1$console $ttyspeed $ttyterm/" \
+			/target/etc/inittab
+		    sed -i -e "s/^\(T$ttyline.*\) -8/\1/" /target/etc/inittab
+		    sed -i -e "s/^\(T$ttyline.* \)-L/\1$flowctrlarg-L/" /target/etc/inittab
+		fi
+		if [ "$upstart_tty1" ]; then
+		    sed -e "s/^\(exec.*getty \).*/\1-L $console $ttyspeed $ttyterm/" \
+			-e "s/tty1/$console/g" \
+			"$upstart_tty1" > "$(upstart_console "$console")"
+		    sed -i -e "s/^\(exec.*\) -8/\1/" "$(upstart_console "$console")"
+		    sed -i -e "s/^\(exec.*\)-L/\1$flowctrlarg-L/" "$(upstart_console "$console")"
+		fi
+		if [ "$(readlink /target/sbin/init)" = "/lib/systemd/systemd" ] ; then
+		    chroot /target systemctl --no-reload --quiet enable serial-getty@"$console".service
 		fi
-		# Enable serial console
-		sed -i -e "s/^#T0\(.*\)ttyS.*/T$ttyline\1$console $ttyspeed $ttyterm/" \
-		    /target/etc/inittab
-		sed -i -e "s/^\(T$ttyline.*\) -8/\1/" /target/etc/inittab
-		sed -i -e "s/^\(T$ttyline.* \)-L/\1$flowctrlarg-L/" /target/etc/inittab
-	fi
-	if [ "$upstart_tty1" ]; then
-		sed -e "s/^\(exec.*getty \).*/\1-L $console $ttyspeed $ttyterm/" \
-		    -e "s/tty1/$console/g" \
-		    "$upstart_tty1" > "$(upstart_console "$console")"
-		sed -i -e "s/^\(exec.*\) -8/\1/" "$(upstart_console "$console")"
-		sed -i -e "s/^\(exec.*\)-L/\1$flowctrlarg-L/" "$(upstart_console "$console")"
-	fi
-	if [ "$(readlink /target/sbin/init)" = "/lib/systemd/systemd" ] ; then
-		chroot /target systemctl --no-reload --quiet enable serial-getty@"$console".service
-	fi
 
-	write_console "$rawconsole" /target/etc/securetty
-	if [ -n "$console" ] && [ "$console" != "$rawconsole" ]; then
-		write_console "$console" /target/etc/securetty
-	fi
-	;;
-esac
+		write_console "$rawconsole" /target/etc/securetty
+		if [ -n "$console" ] && [ "$console" != "$rawconsole" ]; then
+		    write_console "$console" /target/etc/securetty
+		fi
+		;;
+	esac
+done
 
 # Set up virtualized console via onboard service processor (hvsi/hvc)
 DT_ROOT=/proc/device-tree

Attachment: signature.asc
Description: PGP signature


Reply to: