Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not start getty on tty0 to avoid screen corruption #4517

Merged
merged 4 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .spdxignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ pkg/kube/descheduler-job.yaml
pkg/kube/descheduler_rbac.yaml
pkg/kube/lh-cfg-v1.6.2.yaml
pkg/vtpm/swtpm-vtpm/vendor/
pkg/dom0-ztools/rootfs/usr/bin/rungetty.sh
1 change: 1 addition & 0 deletions .yetus/blanks-tabs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
.*\.dts
.*\.md
^.codespellignorelines
pkg/dom0-ztools/rootfs/usr/bin/rungetty.sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you want to ignore blank tabs?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand, because it's not our code originally )

1 change: 1 addition & 0 deletions .yetus/excludes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
^.+/testdata/.+
^.codespellignorelines
eve-tools/bpftrace-compiler/examples/.+\.bt
pkg/dom0-ztools/rootfs/usr/bin/rungetty.sh
12 changes: 8 additions & 4 deletions docs/LOCAL-TUI.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ The client communicates with the server over UNIX socket

The UI is rendered on a local TTY (/dev/tty2) only i.e. on a physical monitor attached to the system. Neither Serial Console nor SSH connection has access to TUI. It is done to ensure the physical presence of the operator.

## /dev/ttyX vs /dev/console
## /dev/ttyX vs /dev/console vs /dev/tty0

There are two distinguishable console devices in Linux `/dev/console` and `/dev/ttyX`. The later points to a particular virtual terminal device and the former points to *currently active* TTY device. The user can switch between virtual terminals by using `Alt+Fx` or `Alt+<,>` keys. When the current TTY is set `/dev/console` tracks this change and always points to to the current terminal
There are three distinguishable console devices in Linux `/dev/console`, `/dev/tty0` and `/dev/ttyX` where X > 0. The latter points to a particular virtual terminal device i.e. a dedicated framebuffer for VGA console. `/dev/tty0` points to *currently active* TTY device. This can be proven by reading `/sys/devices/virtual/tty/tty0/active` file. This file exists only for `/dev/tty0`. On the other hand `/dev/console` may point to several devices at a time. These are devices user specifies in `console=` kernel command line parameters. The list can be obtained by reading `/sys/devices/virtual/tty/console/active` file.

Monitor application is spawned on a `/dev/tty2` using a `openvt` utility while the rest of the applications are spawned on the default kernel console defined by `console=` parameters on the kernel command line. When the application is in focus (`/dev/tty2` is an active console) writing to `/dev/console` which points to the same device corrupts TUI thus it cannot be used by other services in the system to produce the output. At least when `/dev/tty2` is a current console.
The user can switch between virtual terminals by using `Alt+Fx` or `Alt+<,>` keys. When the current TTY is set `/dev/tty0` tracks this change and always points to to the current terminal

From the other hand `/dev/tty` (no digit at the end!) device always points to a TTY *in the context of running process*. This device can be used instead of `/dev/console` by other services for the output.
Monitor application is spawned on a `/dev/tty2` using a `openvt` utility while the rest of the applications are spawned on the default kernel console defined by `console=` parameters on the kernel command line. When the application is in focus (`/dev/tty2` is an active console) writing to `/dev/console` or to `/dev/tty0` which points to the same device corrupts TUI thus it cannot be used by other services in the system to produce the output. At least when `/dev/tty2` is a current console.

On the other hand `/dev/tty` (no digit at the end!) device always points to a TTY *in the context of running process*. This device can be used instead of `/dev/console` by other services for the output.

Mode details can be found in [https://www.kernel.org/doc/Documentation/admin-guide/serial-console.rst](https://www.kernel.org/doc/Documentation/admin-guide/serial-console.rst), [https://www.kernel.org/doc/html/v6.11/admin-guide/devices.html#virtual-consoles-and-the-console-device](https://www.kernel.org/doc/html/v6.11/admin-guide/devices.html#virtual-consoles-and-the-console-device) and in this blog post [https://www.baeldung.com/linux/monitor-keyboard-drivers](https://www.baeldung.com/linux/monitor-keyboard-drivers)

## Limitations of linux terminal

Expand Down
94 changes: 94 additions & 0 deletions pkg/dom0-ztools/rootfs/usr/bin/rungetty.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/bin/sh

infinite_loop() {
while true; do
$@
done
}

# run getty on all known consoles
start_getty() {
tty=${1%,*}
speed=${1#*,}
securetty="$2"
line=
term="linux"
[ "$speed" = "$1" ] && speed=115200

# if console=tty0 is specified on the kernel command line, we should not start a getty on tty0
# but instead start it on the first available tty. tty0 points to the current console, so if
# we start a getty from pillar of debug.enable.console=true we may start it on current tty
# which may be occupied by TUI monitor application and tty will be taken away by getty.
# replacing tty0 with tty1 should be ok because this is the user's intention
if [ "$tty" = "tty0" ]; then
tty="tty1"
fi

# did we already process this tty?
if $(echo "${PROCESSEDTTY}" | grep -q -w "$tty"); then
echo "getty: already processed tty for $tty, not starting twice" | tee /dev/tty
return
fi
# now indicate that we are processing it
PROCESSEDTTY="${PROCESSEDTTY} ${tty}"

# does the device even exist?
if [ ! -c /dev/$tty ]; then
echo "getty: cmdline has console=$tty but /dev/$tty is not a character device; not starting getty for $tty" | tee /dev/tty
return
fi

case "$tty" in
ttyS*|ttyAMA*|ttyUSB*|ttyMFD*)
line="-L"
term="vt100"
;;
tty?)
line=""
speed="38400"
term=""
;;
esac

# are we secure or insecure?
loginargs=
if [ "$INSECURE" == "true" ]; then
loginargs="-a root"
fi

if ! grep -q -w "$tty" "$securetty"; then
# we could not find the tty in securetty, so start a getty but warn that root login will not work
echo "getty: cmdline has console=$tty but does not exist in $securetty; will not be able to log in as root on this tty $tty." | tee /dev/$tty
fi
# respawn forever
echo "getty: starting getty for $tty" | tee /dev/$tty
infinite_loop setsid.getty -w /sbin/agetty $loginargs $line $speed $tty $term &
}


# check if we are namespaced, and, if so, indicate in the PS1
if [ -z "$INITGETTY" ]; then
cat >/etc/profile.d/namespace.sh <<"EOF"
export PS1="(ns: getty) $PS1"
EOF
fi

PROCESSEDTTY=

# check if we have /etc/getty.shadow
ROOTSHADOW=/hostroot/etc/getty.shadow
if [ -f $ROOTSHADOW ]; then
cp $ROOTSHADOW /etc/shadow
# just in case someone forgot a newline
echo >> /etc/shadow
fi

for opt in $(cat /proc/cmdline); do
case "$opt" in
console=*)
start_getty ${opt#console=} /etc/securetty
esac
done

# if we are in a container (not in root init) wait for all our child process to exit; tini will handle subreaping, if necessary
[ -n "$INITGETTY" ] || wait
Loading