OpenBSD console support

Index: common/terminal.c
--- common/terminal.c.orig
+++ common/terminal.c
@@ -26,6 +26,13 @@
 #define K_ENABLE  K_XLATE
 #define K_DISABLE K_RAW
 #define FRSIG     0 // unimplemented
+#elif defined(__OpenBSD__)
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplay_usl_io.h>
+#include <termios.h>
+#define K_ENABLE  K_XLATE
+#define K_DISABLE K_RAW
+#define FRSIG     SIGUSR2
 #else
 #error Unsupported platform
 #endif
@@ -147,6 +154,26 @@ static int get_tty_path(int tty, char path[static TTYP
 	}
 	return 0;
 }
+#elif defined(__OpenBSD__)
+static int get_tty_path(int tty, char path[static TTYPATHLEN]) {
+	assert(tty >= 0);
+
+	// On OpenBSD ttyC0 maps to VT 1.
+	// We subtract one from the requested TTY number to compensate. If the
+	// user asked for TTY 0 (which is special on Linux), we just give them
+	// ttyCcfg.
+	if (tty > 0) {
+		tty--;
+	} else {
+		strncpy(path, "/dev/ttyCcfg", TTYPATHLEN);
+		return 0;
+	}
+
+	if (snprintf(path, TTYPATHLEN, "/dev/ttyC%d", tty) == -1) {
+		return -1;
+	}
+	return 0;
+}
 #else
 #error Unsupported platform
 #endif
@@ -157,6 +184,7 @@ int terminal_open(int vt) {
 		log_errorf("Could not generate tty path: %s", strerror(errno));
 		return -1;
 	}
+	log_debugf("for vt %d open(%s)", vt, path);
 	int fd = open(path, O_RDWR | O_NOCTTY);
 	if (fd == -1) {
 		log_errorf("Could not open target tty: %s", strerror(errno));
@@ -166,7 +194,7 @@ int terminal_open(int vt) {
 }
 
 int terminal_current_vt(int fd) {
-#if defined(__linux__) || defined(__NetBSD__)
+#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
 	struct vt_stat st;
 	int res = ioctl(fd, VT_GETSTATE, &st);
 	if (res == -1) {
@@ -193,7 +221,8 @@ int terminal_current_vt(int fd) {
 }
 
 int terminal_set_process_switching(int fd, bool enable) {
-	log_debugf("Setting process switching to %d", enable);
+	char *debugstr = enable ? "process" : "auto";
+	log_debugf("Setting process switching to %s", debugstr);
 	struct vt_mode mode = {
 		.mode = enable ? VT_PROCESS : VT_AUTO,
 		.waitv = 0,
@@ -201,10 +230,22 @@ int terminal_set_process_switching(int fd, bool enable
 		.acqsig = enable ? SIGUSR2 : 0,
 		.frsig = FRSIG,
 	};
-
+	struct vt_mode current_mode;
+	if (ioctl(fd, VT_GETMODE, &current_mode) == -1) {
+		log_errorf("Could not query VT mode for %d: %s",
+		    fd, strerror(errno));
+		return -1;
+	}
+	if (current_mode.mode == mode.mode &&
+	    current_mode.relsig == mode.relsig &&
+	    current_mode.acqsig == mode.acqsig &&
+	    current_mode.frsig == mode.frsig) {
+		log_debugf("%s: %d already in mode %d", __func__, fd, enable);
+		return 0;
+	}
 	if (ioctl(fd, VT_SETMODE, &mode) == -1) {
-		log_errorf("Could not set VT mode to %s process switching: %s",
-			   enable ? "enable" : "disable", strerror(errno));
+		log_errorf("Could not set VT mode to %s switching: %s",
+			   debugstr, strerror(errno));
 		return -1;
 	}
 	return 0;
@@ -241,19 +282,38 @@ int terminal_ack_acquire(int fd) {
 }
 
 int terminal_set_keyboard(int fd, bool enable) {
+#ifndef __OpenBSD__
 	log_debugf("Setting KD keyboard state to %d", enable);
 	if (ioctl(fd, KDSKBMODE, enable ? K_ENABLE : K_DISABLE) == -1) {
 		log_errorf("Could not set KD keyboard mode to %s: %s",
 			   enable ? "enabled" : "disabled", strerror(errno));
 		return -1;
 	}
+#else
+	int mode = enable ? WSKBD_TRANSLATED : WSKBD_RAW;
+	char *debugstr = enable ? "translated" : "raw";
+
+	if (mode == WSKBD_RAW) {
+		/* XXX ignore for now */;
+		log_debugf("NOT setting KD keyboard state to %s", debugstr);
+	} else if (ioctl(fd, WSKBDIO_SETMODE, &mode) == -1) {
+		log_errorf("Could not set keyboard mode to %s: %s",
+		    debugstr, strerror(errno));
+	}
+#endif
 #if defined(__FreeBSD__)
+	/* XXX enable code path on OpenBSD */
 	struct termios tios;
 	if (tcgetattr(fd, &tios) == -1) {
 		log_errorf("Could not set get terminal mode: %s", strerror(errno));
 		return -1;
 	}
 	if (enable) {
+		/*
+		 * We could save the initial terminal state instead of
+		 * using new function cfmakesane.
+		 */
+		extern void cfmakesane(struct termios *);
 		cfmakesane(&tios);
 	} else {
 		cfmakeraw(&tios);
@@ -268,11 +328,23 @@ int terminal_set_keyboard(int fd, bool enable) {
 }
 
 int terminal_set_graphics(int fd, bool enable) {
+#ifndef __OpenBSD__
 	log_debugf("Setting KD graphics state to %d", enable);
 	if (ioctl(fd, KDSETMODE, enable ? KD_GRAPHICS : KD_TEXT) == -1) {
 		log_errorf("Could not set KD graphics mode to %s: %s", enable ? "graphics" : "text",
 			   strerror(errno));
 		return -1;
 	}
+#else
+	int mode = enable ? WSDISPLAYIO_MODE_MAPPED : WSDISPLAYIO_MODE_EMUL;
+	char *debugstr = enable ? "mapped" : "emul";
+
+	log_debugf("Setting KD graphics state to %s", debugstr);
+	if (ioctl(fd, WSDISPLAYIO_SMODE, &mode) == -1) {
+		log_errorf("Could not set graphics mode to %s: %s",
+		    enable ? "mapped" : "emul", strerror(errno));
+		return -1;
+	}
+#endif
 	return 0;
 }
