From a8f7d33f47cc28732cd04573ae1fb6a1ca6e9617 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
Date: Mon, 24 Sep 2012 07:58:29 +0300
Subject: [PATCH 05/11] fbsplash: support console switching
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Timo Teräs <timo.teras@iki.fi>
---
 miscutils/fbsplash.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 76 insertions(+), 7 deletions(-)

diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index fc6c9b953..ec5947314 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -47,7 +47,7 @@
 //kbuild:lib-$(CONFIG_FBSPLASH) += fbsplash.o
 
 //usage:#define fbsplash_trivial_usage
-//usage:       "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]"
+//usage:       "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD] [-T tty]"
 //usage:#define fbsplash_full_usage "\n\n"
 //usage:       "	-s	Image"
 //usage:     "\n	-c	Hide cursor"
@@ -57,11 +57,17 @@
 //usage:     "\n			BAR_R,BAR_G,BAR_B"
 //usage:     "\n	-f	Control pipe (else exit after drawing image)"
 //usage:     "\n			commands: 'NN' (% for progress bar) or 'exit'"
+//usage:     "\n	-T	Switch to TTY to hide all console messages"
 
 #include "libbb.h"
 #include "common_bufsiz.h"
 #include <linux/fb.h>
 
+#include <sys/vt.h>
+#include <sys/ioctl.h>
+#include <linux/tiocl.h>
+#include <linux/kd.h>
+
 /* If you want logging messages on /tmp/fbsplash.log... */
 #define DEBUG 0
 
@@ -73,6 +79,8 @@ struct globals {
 	unsigned char *addr;	// pointer to framebuffer memory
 	unsigned ns[7];		// n-parameters
 	const char *image_filename;
+	int silent_tty, fd_tty_s;
+	bool do_not_draw;
 	struct fb_var_screeninfo scr_var;
 	struct fb_fix_screeninfo scr_fix;
 	unsigned bytes_per_pixel;
@@ -483,6 +491,11 @@ static void init(const char *cfg_filename)
 	config_close(parser);
 }
 
+static void sighandler(int sig)
+{
+	ioctl(G.fd_tty_s, VT_RELDISP, sig == SIGUSR1 ? 1 : 2);
+	G.do_not_draw = (sig != SIGUSR2);
+}
 
 int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int fbsplash_main(int argc UNUSED_PARAM, char **argv)
@@ -492,6 +505,9 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 	char *num_buf;
 	unsigned num;
 	bool bCursorOff;
+	int fd_tty0, active_vt;
+	struct vt_stat vtstat;
+	struct vt_mode vt;
 
 	INIT_G();
 
@@ -499,8 +515,10 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 	fb_device = "/dev/fb0";
 	cfg_filename = NULL;
 	fifo_filename = NULL;
-	bCursorOff = 1 & getopt32(argv, "cs:d:i:f:",
-			&G.image_filename, &fb_device, &cfg_filename, &fifo_filename);
+	opt_complementary = "T+"; // numeric params
+	bCursorOff = 1 & getopt32(argv, "cs:d:i:f:T:",
+			&G.image_filename, &fb_device, &cfg_filename, &fifo_filename,
+			&G.silent_tty);
 
 	// parse configuration file
 	if (cfg_filename)
@@ -510,11 +528,43 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 	if (!G.image_filename)
 		bb_show_usage();
 
+	fd_tty0 = get_console_fd_or_die();
+	if (G.silent_tty) {
+		char buf[16];
+
+		/* Initialize TTY */
+		bb_signals((1LL << SIGUSR1) | (1LL << SIGUSR2), sighandler);
+		snprintf(buf, sizeof(buf), "/dev/tty%d", G.silent_tty);
+		G.fd_tty_s = xopen(buf, O_RDWR | O_NOCTTY);
+
+		/* Activate TTY */
+		xioctl(fd_tty0, VT_GETSTATE, &vtstat);
+		active_vt = vtstat.v_active;
+		console_make_active(fd_tty0, G.silent_tty);
+
+		/* Get notifications on console changes */
+		vt.mode   = VT_PROCESS;
+		vt.waitv  = 0;
+		vt.relsig = SIGUSR1;
+		vt.acqsig = SIGUSR2;
+		ioctl(G.fd_tty_s, VT_SETMODE, &vt);
+
+		/* Redirect all kernel messages to tty1 so that they don't get
+		 * printed over our silent splash image. And clear it. */
+		buf[0] = TIOCL_SETKMSGREDIRECT;
+		buf[1] = 1;
+		ioctl(G.fd_tty_s, TIOCLINUX, buf);
+		full_write(G.fd_tty_s, "\e[H\e[2J" "\e[?17;0c", 7+8);
+		ioctl(G.fd_tty_s, KDSETMODE, KD_GRAPHICS);
+	} else {
+		G.fd_tty_s = STDOUT_FILENO;
+	}
+
 	fb_open(fb_device);
 
 	if (fifo_filename && bCursorOff) {
 		// hide cursor (BEFORE any fb ops)
-		full_write(STDOUT_FILENO, "\033[?25l", 6);
+		full_write(G.fd_tty_s, "\033[?25l", 6);
 	}
 
 	fb_drawimage();
@@ -522,6 +572,7 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 	if (!fifo_filename)
 		return EXIT_SUCCESS;
 
+	sig_block(SIGUSR1);
 	fp = xfopen_stdin(fifo_filename);
 	if (fp != stdin) {
 		// For named pipes, we want to support this:
@@ -537,8 +588,9 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 		// and become an additional writer :)
 		open(fifo_filename, O_WRONLY); // errors are ignored
 	}
-
 	fb_drawprogressbar(0);
+	sig_unblock(SIGUSR1);
+
 	// Block on read, waiting for some input.
 	// Use of <stdio.h> style I/O allows to correctly
 	// handle a case when we have many buffered lines
@@ -553,12 +605,29 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
 #if DEBUG
 			DEBUG_MESSAGE(itoa(num));
 #endif
-			fb_drawprogressbar(num);
+			sig_block(SIGUSR1);
+			if (!G.do_not_draw)
+				fb_drawprogressbar(num);
+			sig_unblock(SIGUSR1);
 		}
 		free(num_buf);
 	}
 
-	if (bCursorOff) // restore cursor
+	if (G.silent_tty) {
+		usleep(100*1000);
+
+		ioctl(G.fd_tty_s, VT_RELDISP, 1);
+		ioctl(G.fd_tty_s, KDSETMODE, KD_TEXT);
+		vt.mode  = VT_AUTO;
+		vt.waitv = 0;
+		ioctl(G.fd_tty_s, VT_SETMODE, &vt);
+		close(G.fd_tty_s);
+
+		xioctl(fd_tty0, VT_GETSTATE, &vtstat);
+		if (vtstat.v_active == G.silent_tty)
+			console_make_active(fd_tty0, active_vt);
+		ioctl(fd_tty0, VT_DISALLOCATE, (void *)(ptrdiff_t)G.silent_tty);
+	} else if (bCursorOff) // restore cursor
 		full_write(STDOUT_FILENO, "\033[?25h", 6);
 
 	return EXIT_SUCCESS;
-- 
2.13.2