[kbd] [PATCH] kbd_mode: Add -f option and deny dangerous mode switches without it

Balint Reczey balint at balintreczey.hu
Tue Apr 23 18:38:07 MSK 2019


kbd_mode(1) already had a warning but kbd_mode still performed all
mode changes even when they made keyboards unusable.

The added flag let's the callers try safe changes or force the risky
ones. This change may break scripts but the broken scripts most likely
made the keyboard unusable and should be updated.

Original bug report at:
https://bugs.launchpad.net/ubuntu/+source/kbd/+bug/520546

Signed-off-by: Balint Reczey <balint.reczey at canonical.com>
---
 docs/man/man1/kbd_mode.1 |  8 +++--
 src/kbd_mode.c           | 65 ++++++++++++++++++++++++++++------------
 2 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/docs/man/man1/kbd_mode.1 b/docs/man/man1/kbd_mode.1
index 960b36c..f605c02 100644
--- a/docs/man/man1/kbd_mode.1
+++ b/docs/man/man1/kbd_mode.1
@@ -7,6 +7,8 @@ kbd_mode \- report or set the keyboard mode
 [
 .I -a | -u | -k | -s 
 ] [
+.I -f
+] [
 .I -C CONSOLE
 ]
 .SH DESCRIPTION
@@ -36,11 +38,13 @@ kbd_mode operates on the console specified by the "\-C" option; if there
 is none, the console associated with stdin is used.
 
 Warning: changing the keyboard mode, other than between ASCII and
-Unicode, will probably make your keyboard unusable.
+Unicode, will probably make your keyboard unusable. Set the "\-f" option
+to force such changes.
 This command is only meant for use (say via remote login)
 when some program left your keyboard in the wrong state.
 Note that in some obsolete versions of this program the "\-u"
-option was a synonym for "\-s".
+option was a synonym for "\-s" and older versions of this program may
+not recognize the "\-f" option.
 .SH "SEE ALSO"
 .BR loadkeys (1)
 
diff --git a/src/kbd_mode.c b/src/kbd_mode.c
index 5d291b7..956ea51 100644
--- a/src/kbd_mode.c
+++ b/src/kbd_mode.c
@@ -20,13 +20,34 @@
 static void __attribute__((noreturn))
 usage(void)
 {
-	fprintf(stderr, _("usage: kbd_mode [-a|-u|-k|-s] [-C device]\n"));
+	fprintf(stderr, _("usage: kbd_mode [-a|-u|-k|-s] [-f] [-C device]\n"));
 	exit(EXIT_FAILURE);
 }
 
+static void
+fprint_mode(FILE *stream, int  mode)
+{
+	switch (mode) {
+		case K_RAW:
+			fprintf(stream, _("The keyboard is in raw (scancode) mode\n"));
+			break;
+		case K_MEDIUMRAW:
+			fprintf(stream, _("The keyboard is in mediumraw (keycode) mode\n"));
+			break;
+		case K_XLATE:
+			fprintf(stream, _("The keyboard is in the default (ASCII) mode\n"));
+			break;
+		case K_UNICODE:
+			fprintf(stream, _("The keyboard is in Unicode (UTF-8) mode\n"));
+			break;
+		default:
+			fprintf(stream, _("The keyboard is in some unknown mode\n"));
+        }
+}
+
 int main(int argc, char *argv[])
 {
-	int fd, mode, c, n = 0;
+	int fd, mode, orig_mode, c, n = 0, force = 0;
 	char *console = NULL;
 
 	set_progname(argv[0]);
@@ -38,7 +59,7 @@ int main(int argc, char *argv[])
 	if (argc == 2 && !strcmp(argv[1], "-V"))
 		print_version_and_exit();
 
-	while ((c = getopt(argc, argv, "auskC:")) != EOF) {
+	while ((c = getopt(argc, argv, "auskfC:")) != EOF) {
 		switch (c) {
 			case 'a':
 				if (n > 0)
@@ -64,6 +85,9 @@ int main(int argc, char *argv[])
 				mode = K_MEDIUMRAW;
 				n++;
 				break;
+			case 'f':
+				force = 1;
+				break;
 			case 'C':
 				if (!optarg || !optarg[0])
 					usage();
@@ -82,25 +106,28 @@ int main(int argc, char *argv[])
 		if (ioctl(fd, KDGKBMODE, &mode)) {
 			kbd_error(EXIT_FAILURE, errno, "ioctl KDGKBMODE");
 		}
-		switch (mode) {
-			case K_RAW:
-				printf(_("The keyboard is in raw (scancode) mode\n"));
-				break;
-			case K_MEDIUMRAW:
-				printf(_("The keyboard is in mediumraw (keycode) mode\n"));
-				break;
-			case K_XLATE:
-				printf(_("The keyboard is in the default (ASCII) mode\n"));
-				break;
-			case K_UNICODE:
-				printf(_("The keyboard is in Unicode (UTF-8) mode\n"));
-				break;
-			default:
-				printf(_("The keyboard is in some unknown mode\n"));
-		}
+		fprint_mode(stdout, mode);
 		return EXIT_SUCCESS;
 	}
 
+	if (force == 0) {
+		/* only perform safe mode switches */
+		if (ioctl(fd, KDGKBMODE, &orig_mode)) {
+			kbd_error(EXIT_FAILURE, errno, "ioctl KDGKBMODE");
+		}
+
+		if (mode == orig_mode) {
+			/* skip mode change */
+			return EXIT_SUCCESS;
+		}
+
+		if ((mode == K_XLATE && orig_mode != K_UNICODE) || (mode == K_UNICODE && orig_mode != K_XLATE)) {
+			fprint_mode(stderr, orig_mode);
+			fprintf(stderr, _("Changing to the requested mode may make "
+				"your keyboard unusable, please use -f to force the change.\n"));
+			return EXIT_FAILURE;
+		}
+	}
 	if (ioctl(fd, KDSKBMODE, mode)) {
 		kbd_error(EXIT_FAILURE, errno, "ioctl KDSKBMODE");
 	}
-- 
2.17.1



More information about the kbd mailing list