Sophie

Sophie

distrib > Mandriva > 2010.1 > x86_64 > by-pkgid > dc28496d55304e5c3f2fae8fb6a5b53a > files > 2

kbd-1.15.2-2.1mdv2010.2.src.rpm

From 1db6f826e68b700e7a657c2e87a4e25a56f53d90 Mon Sep 17 00:00:00 2001
From: Daniel Drake <d.drake@mmm.com>
Date: Wed, 30 Jun 2010 17:30:44 +0200
Subject: [PATCH] chvt: add --userwait option

At http://bugs.gentoo.org/159729 we see chvt hanging in some scenario's.
As the solution to this is not immediately obvious, add a --userwait option
which repeatedly tries changing the terminal until the change has taken
place.
---
 man/man1/chvt.1 |   10 +++++++
 src/chvt.c      |   80 ++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 77 insertions(+), 13 deletions(-)

diff --git a/man/man1/chvt.1 b/man/man1/chvt.1
index c7b9105..11cc9bd 100644
--- a/man/man1/chvt.1
+++ b/man/man1/chvt.1
@@ -4,6 +4,9 @@
 chvt \- change foreground virtual terminal
 .SH SYNOPSIS
 .B chvt
+[
+.B --userwait
+]
 .I N
 .SH DESCRIPTION
 The command
@@ -21,3 +24,10 @@ The key combination
 (with
 .I N
 in the range 1-12) usually has a similar effect.
+.LP
+The
+.B --userwait
+option causes the system to loop in userspace waiting for the new terminal
+to become active, as opposed to the kernel-side
+.I VT_WAITACTIVE
+ioctl.
diff --git a/src/chvt.c b/src/chvt.c
index 1e12552..0e5f352 100644
--- a/src/chvt.c
+++ b/src/chvt.c
@@ -7,13 +7,43 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
 #include "getfd.h"
 #include "nls.h"
 #include "version.h"
 
+#define USER_WAIT_SLEEP_US		100000
+#define USER_WAIT_MAX_ITERATIONS	50
+
+static int fd;
+
+static void chvt(int num)
+{
+    if (ioctl(fd,VT_ACTIVATE,num)) {
+	perror("VT_ACTIVATE");
+	exit(1);
+    }
+}
+
+static int fgconsole(void)
+{
+    struct vt_stat vtstat;
+    if (ioctl(fd, VT_GETSTATE, &vtstat)) {
+	perror("VT_GETSTATE");
+	exit(1);
+    }
+    return vtstat.v_active;
+}
+
 int
 main(int argc, char *argv[]) {
-    int fd, num;
+    int c, num;
+    int user_wait = 0;
+    const struct option long_opts[] = {
+	{ "version",	no_argument, NULL, 'V' },
+	{ "userwait",	no_argument, NULL, 'u' },
+    };
 
     set_progname(argv[0]);
 
@@ -21,22 +51,46 @@ main(int argc, char *argv[]) {
     bindtextdomain(PACKAGE_NAME, LOCALEDIR);
     textdomain(PACKAGE_NAME);
 
-    if (argc == 2 && !strcmp(argv[1], "-V"))
-	print_version_and_exit();
+    while ((c = getopt_long(argc, argv, "Vu", long_opts, NULL)) != -1) {
+	switch (c) {
+	    case 'V':
+		print_version_and_exit();
+	    case 'u':
+		user_wait = 1;
+		break;
+	}
+    }
 
-    if (argc != 2) {
-	fprintf(stderr, _("usage: chvt N\n"));
+    if (optind >= argc) {
+	fprintf(stderr, _("usage: chvt [--userwait] N\n"));
 	exit(1);
     }
+
     fd = getfd(NULL);
-    num = atoi(argv[1]);
-    if (ioctl(fd,VT_ACTIVATE,num)) {
-	perror("chvt: VT_ACTIVATE");
-	exit(1);
-    }
-    if (ioctl(fd,VT_WAITACTIVE,num)) {
-	perror("VT_WAITACTIVE");
-	exit(1);
+    num = atoi(argv[optind++]);
+    chvt(num);
+
+    if (user_wait) {
+    	int active = 0;
+	int i;
+	for (i = 0; i < USER_WAIT_MAX_ITERATIONS; i++) {
+	    if (fgconsole() == num) {
+	    	active = 1;
+	    	break;
+	    }
+
+	    chvt(num);
+	    usleep(USER_WAIT_SLEEP_US);
+	}
+	if (!active) {
+	    fprintf(stderr, _("VT change timed out\n"));
+	    exit(1);
+	}
+    } else {
+	if (ioctl(fd,VT_WAITACTIVE,num)) {
+	    perror("VT_WAITACTIVE");
+	    exit(1);
+	}
     }
     exit(0);
 }
-- 
1.7.1