Takashi Iwai dd6e2e
From f59fcad27535c7efd8017e084cf215ece392a85f Mon Sep 17 00:00:00 2001
Takashi Iwai dd6e2e
From: nick black <dankamongmen@gmail.com>
Takashi Iwai dd6e2e
Date: Mon, 30 Aug 2021 04:56:15 -0400
Takashi Iwai dd6e2e
Subject: [PATCH] console: consume APC, DM, DCS
Takashi Iwai dd6e2e
Git-commit: 3a2b2eb55681158d3e3ef464fbf47574cf0c517c
Takashi Iwai dd6e2e
Patch-mainline: v5.15-rc1
Takashi Iwai dd6e2e
References: stable-5.14.8
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
commit 3a2b2eb55681158d3e3ef464fbf47574cf0c517c upstream.
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
The Linux console's VT102 implementation already consumes OSC
Takashi Iwai dd6e2e
("Operating System Command") sequences, probably because that's how
Takashi Iwai dd6e2e
palette changes are transmitted.
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
In addition to OSC, there are three other major clases of ANSI control
Takashi Iwai dd6e2e
Strings: APC ("Application Program Command"), PM ("Privacy Message"),
Takashi Iwai dd6e2e
and DCS ("Device Control String").  They are handled similarly to OSC in
Takashi Iwai dd6e2e
terms of termination.
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
Source: vt100.net
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
Add three new enumerated states, one for each of these types.  All three
Takashi Iwai dd6e2e
are handled the same way right now--they simply consume input until
Takashi Iwai dd6e2e
terminated.  I hope to expand upon this firmament in the future.  Add
Takashi Iwai dd6e2e
new predicate ansi_control_string(), returning true for any of these
Takashi Iwai dd6e2e
states.  Replace explicit checks against ESosc with calls to this
Takashi Iwai dd6e2e
function.  Transition to these states appropriately from the escape
Takashi Iwai dd6e2e
initiation (ESesc) state.
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
This was motivated by the following Notcurses bugs:
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
 https://github.com/dankamongmen/notcurses/issues/2050
Takashi Iwai dd6e2e
 https://github.com/dankamongmen/notcurses/issues/1828
Takashi Iwai dd6e2e
 https://github.com/dankamongmen/notcurses/issues/2069
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
where standard VT sequences are not consumed by the Linux console.  It's
Takashi Iwai dd6e2e
not necessary that the Linux console *support* these sequences, but it
Takashi Iwai dd6e2e
ought *consume* these well-specified classes of sequences.
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
Tested by sending a variety of escape sequences to the console, and
Takashi Iwai dd6e2e
verifying that they still worked, or were now properly consumed.
Takashi Iwai dd6e2e
Verified that the escapes were properly terminated at a generic level.
Takashi Iwai dd6e2e
Verified that the Notcurses tools continued to show expected output on
Takashi Iwai dd6e2e
the Linux console, except now without escape bleedthrough.
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
Link: https://lore.kernel.org/lkml/YSydL0q8iaUfkphg@schwarzgerat.orthanc/
Takashi Iwai dd6e2e
Signed-off-by: nick black <dankamongmen@gmail.com>
Takashi Iwai dd6e2e
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Takashi Iwai dd6e2e
Cc: Jiri Slaby <jirislaby@kernel.org>
Takashi Iwai dd6e2e
Cc: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Takashi Iwai dd6e2e
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Takashi Iwai dd6e2e
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Takashi Iwai dd6e2e
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Takashi Iwai dd6e2e
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
---
Takashi Iwai dd6e2e
 drivers/tty/vt/vt.c | 31 +++++++++++++++++++++++++++----
Takashi Iwai dd6e2e
 1 file changed, 27 insertions(+), 4 deletions(-)
Takashi Iwai dd6e2e
Takashi Iwai dd6e2e
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
Takashi Iwai dd6e2e
index ef981d3b7bb4..cb72393f92d3 100644
Takashi Iwai dd6e2e
--- a/drivers/tty/vt/vt.c
Takashi Iwai dd6e2e
+++ b/drivers/tty/vt/vt.c
Takashi Iwai dd6e2e
@@ -2059,7 +2059,7 @@ static void restore_cur(struct vc_data *vc)
Takashi Iwai dd6e2e
 
Takashi Iwai dd6e2e
 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
Takashi Iwai dd6e2e
 	EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
Takashi Iwai dd6e2e
-	ESpalette, ESosc };
Takashi Iwai dd6e2e
+	ESpalette, ESosc, ESapc, ESpm, ESdcs };
Takashi Iwai dd6e2e
 
Takashi Iwai dd6e2e
 /* console_lock is held (except via vc_init()) */
Takashi Iwai dd6e2e
 static void reset_terminal(struct vc_data *vc, int do_clear)
Takashi Iwai dd6e2e
@@ -2133,20 +2133,28 @@ static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
Takashi Iwai dd6e2e
 		vc->vc_translate = set_translate(*charset, vc);
Takashi Iwai dd6e2e
 }
Takashi Iwai dd6e2e
 
Takashi Iwai dd6e2e
+/* is this state an ANSI control string? */
Takashi Iwai dd6e2e
+static bool ansi_control_string(unsigned int state)
Takashi Iwai dd6e2e
+{
Takashi Iwai dd6e2e
+	if (state == ESosc || state == ESapc || state == ESpm || state == ESdcs)
Takashi Iwai dd6e2e
+		return true;
Takashi Iwai dd6e2e
+	return false;
Takashi Iwai dd6e2e
+}
Takashi Iwai dd6e2e
+
Takashi Iwai dd6e2e
 /* console_lock is held */
Takashi Iwai dd6e2e
 static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
Takashi Iwai dd6e2e
 {
Takashi Iwai dd6e2e
 	/*
Takashi Iwai dd6e2e
 	 *  Control characters can be used in the _middle_
Takashi Iwai dd6e2e
-	 *  of an escape sequence.
Takashi Iwai dd6e2e
+	 *  of an escape sequence, aside from ANSI control strings.
Takashi Iwai dd6e2e
 	 */
Takashi Iwai dd6e2e
-	if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */
Takashi Iwai dd6e2e
+	if (ansi_control_string(vc->vc_state) && c >= 8 && c <= 13)
Takashi Iwai dd6e2e
 		return;
Takashi Iwai dd6e2e
 	switch (c) {
Takashi Iwai dd6e2e
 	case 0:
Takashi Iwai dd6e2e
 		return;
Takashi Iwai dd6e2e
 	case 7:
Takashi Iwai dd6e2e
-		if (vc->vc_state == ESosc)
Takashi Iwai dd6e2e
+		if (ansi_control_string(vc->vc_state))
Takashi Iwai dd6e2e
 			vc->vc_state = ESnormal;
Takashi Iwai dd6e2e
 		else if (vc->vc_bell_duration)
Takashi Iwai dd6e2e
 			kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
Takashi Iwai dd6e2e
@@ -2207,6 +2215,12 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
Takashi Iwai dd6e2e
 		case ']':
Takashi Iwai dd6e2e
 			vc->vc_state = ESnonstd;
Takashi Iwai dd6e2e
 			return;
Takashi Iwai dd6e2e
+		case '_':
Takashi Iwai dd6e2e
+			vc->vc_state = ESapc;
Takashi Iwai dd6e2e
+			return;
Takashi Iwai dd6e2e
+		case '^':
Takashi Iwai dd6e2e
+			vc->vc_state = ESpm;
Takashi Iwai dd6e2e
+			return;
Takashi Iwai dd6e2e
 		case '%':
Takashi Iwai dd6e2e
 			vc->vc_state = ESpercent;
Takashi Iwai dd6e2e
 			return;
Takashi Iwai dd6e2e
@@ -2224,6 +2238,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
Takashi Iwai dd6e2e
 			if (vc->state.x < VC_TABSTOPS_COUNT)
Takashi Iwai dd6e2e
 				set_bit(vc->state.x, vc->vc_tab_stop);
Takashi Iwai dd6e2e
 			return;
Takashi Iwai dd6e2e
+		case 'P':
Takashi Iwai dd6e2e
+			vc->vc_state = ESdcs;
Takashi Iwai dd6e2e
+			return;
Takashi Iwai dd6e2e
 		case 'Z':
Takashi Iwai dd6e2e
 			respond_ID(tty);
Takashi Iwai dd6e2e
 			return;
Takashi Iwai dd6e2e
@@ -2520,8 +2537,14 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
Takashi Iwai dd6e2e
 		vc_setGx(vc, 1, c);
Takashi Iwai dd6e2e
 		vc->vc_state = ESnormal;
Takashi Iwai dd6e2e
 		return;
Takashi Iwai dd6e2e
+	case ESapc:
Takashi Iwai dd6e2e
+		return;
Takashi Iwai dd6e2e
 	case ESosc:
Takashi Iwai dd6e2e
 		return;
Takashi Iwai dd6e2e
+	case ESpm:
Takashi Iwai dd6e2e
+		return;
Takashi Iwai dd6e2e
+	case ESdcs:
Takashi Iwai dd6e2e
+		return;
Takashi Iwai dd6e2e
 	default:
Takashi Iwai dd6e2e
 		vc->vc_state = ESnormal;
Takashi Iwai dd6e2e
 	}
Takashi Iwai dd6e2e
-- 
Takashi Iwai dd6e2e
2.26.2
Takashi Iwai dd6e2e