On 2019-01-25 03:45 +0000, Wookey wrote: > So, unless anyone can see a problem with this approach, I'll finish > this off. Trying to do it with separate /var/run/consoles and > /var/run/extra-consoles files was getting very messy.
OK. This took way longer than I hoped as it was not entirely trivial to get everything working. Attached is a patch which provides working multiconsole support for linux (not hurd or bsd, sorry). After getting the proc/console choosing code working nicely the installer was still mysteriously not working (nothing on consoles except debug) unless I let it respawn in which case it sort of worked (things appeared but input oddness and continuous respawning isn't much use to anyone). I was confused for a while as to what was going on but eventually worked it out. Just to recap: The objective here is to run D-I on all the enabled consoles, (and ideally not fiddle with the code any more than is needed). First step was upgrading the console parsing code to use /proc/consoles to get the list, noting the preferred console if there is one marked as such. The main complication is that reopen-consoles is run twice by init, once with debian-installer-startup and once with debian-installer: # main rc script ::sysinit:/sbin/reopen-console /sbin/debian-installer-startup # main setup program ::respawn:/sbin/reopen-console /sbin/debian-installer The first run of reopen-console works out which consoles to use, and writes it in a file, (/var/run/console-devices), the second run just uses that file. debian-installer-startup is just a shell script that runs through all the debian-installer-startup.d rc scripts, like S01mount, S04countcpus-linux-hppa, S10syslog. debian-installer actually runs the installer, on the second invocation of reopen-consoles. So the original plan was just to run $@ (debian-installer) on the found consoles. But doing that for the rc scripts is not helpful. Most of it is idempotent, but you end up with two syslogs and two klogds and running it all twice on different consoles really isn't right. So I added an --all-consoles option to declare that we want something (/sbin/debian-installer in this case) run on all the consoles. # main rc script ::sysinit:/sbin/reopen-console /sbin/debian-installer-startup # main setup program ::respawn:/sbin/reopen-console --all-consoles /sbin/debian-installer It's also worth noting that 'steal-ctty' cannot set the process as 'controlling tty' when two are run, because only one process can be controlling tty in a session. So I did add error checking to that (it had none before), but had to take it out again for the 'set ctty' IOCTL as it's correct for it to fail in the muti-console case. So what happens now is that the rc-scripts are run on the 'preferred' console (or the first console listed if none are marked preferred), then D-I is run on all of them. It does not return to init in this case (as previously discussed). This is an important improvement so despite it having ended up rather late in the day, I hope we can include this for buster. I'm happy to do more work on tidying up any breakage if we find any. Future work: All this faffage has made me realise that a better approach to all this would probably be to get rid of all this 'steal-ctty' bodgery, and use init to do it's job: it's designed to run multiple things on multiple consoles, and deal with file handles and them failing etc. The catch is that to make this work we'd have to use sysinit: to run the console-choosing code, then write a new inittab containing one respawn:/sbin/debian-installer for each console instance, then HUP init. This should do exactly the right thing (assuming that busybox init isn't too thick to get HUPing right). That is way cleaner and I'm happy to have a go at that, but it feels more intrusive and unless I'm very lucky it may take a while so I sugest we go with the above for now, as it works already. One bug I just noticed in the bit we did today is that the 'default' preferred console (for when one is not indicated by the kernel) avoids the existence-check for the /dev file, so that should be improved. It's not hard, but I'll resist doing it now and sending an untested patch :-) 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..32dfd24 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. +# 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 + # prefer first console listed if none marked preferred + if [ "$preferred" = "" ]; then + preferred="$cons" fi - fi + 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 + # '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 + for cons in $consoles + do + echo "/dev/$cons " >> /var/run/console-devices + done + echo "/dev/$preferred " > /var/run/console-preferred +fi - if [ -z "$console" ]; then - # Still nothing? Default to /dev/console. - console=console - fi - echo /dev/$console > /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 -# Some other session may have it as ctty. Steal it from them -exec /sbin/steal-ctty $(cat /var/run/console-device) "$@" + 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; }
signature.asc
Description: PGP signature