chvt: add --userwait option From: Daniel Drake 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. Index: kbd-1.14.1/man/man1/chvt.1 =================================================================== --- kbd-1.14.1.orig/man/man1/chvt.1 +++ kbd-1.14.1/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. Index: kbd-1.14.1/src/chvt.c =================================================================== --- kbd-1.14.1.orig/src/chvt.c +++ kbd-1.14.1/src/chvt.c @@ -7,13 +7,43 @@ #include #include #include +#include +#include #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); }