diff options
Diffstat (limited to 'toys/pending/openvt.c')
-rw-r--r-- | toys/pending/openvt.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/toys/pending/openvt.c b/toys/pending/openvt.c new file mode 100644 index 00000000..5aecd945 --- /dev/null +++ b/toys/pending/openvt.c @@ -0,0 +1,134 @@ +/* openvt.c - Run a program on a new VT + * + * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com> + * + * No Standard + +USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT)) + +config OPENVT + bool "openvt" + default n + help + usage: openvt [-c N] [-s] [-w] [--] [command [command_options]] + + start a program on a new virtual terminal (VT) + + -c N Use VT N + -s Switch to new VT + -w Wait for command to exit + if -s and -w option used together, switch back + to originating VT when command completes +*/ + +#define FOR_openvt +#include "toys.h" +#include <linux/vt.h> +#include <linux/kd.h> + +GLOBALS( + unsigned long vt_num; +) + +int find_console_fd(void) +{ + char *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"}; + int i; + int fd; + char arg; + + for (i = 0; i < 3; i++) { + fd = open(console_name[i], O_RDWR); + if (fd < 0 && errno == EACCES) + fd = open(console_name[i], O_RDONLY); + + if (fd < 0 && errno == EACCES) + fd = open(console_name[i], O_WRONLY); + + if (fd >= 0) { + arg = 0; + if (0 == ioctl(fd, KDGKBTYPE, &arg)) + return fd; + else + close(fd); + } + } + + /* check std fd 0, 1 and 2 */ + for (fd = 0; fd < 3; fd++) { + arg = 0; + if (0 == ioctl(fd, KDGKBTYPE, &arg)) + return fd; + } + + return -1; +} + +int xvtnum(int fd) +{ + int ret; + + ret = ioctl(fd, VT_OPENQRY, (int *)&TT.vt_num); + if (ret != 0 || TT.vt_num <= 0) perror_exit("can't find open VT"); + + return TT.vt_num; +} + +void openvt_main(void) +{ + int fd = -1, vt_fd = -1, pid, ret = 0; + struct vt_stat vstate; + + if (!(toys.optflags & FLAG_c)) { + // check if fd 0,1 or 2 is already opened + for (fd = 0; fd < 3; fd++) + if (!ioctl(fd, VT_GETSTATE, &vstate)) { + ret = xvtnum(fd); + break; + } + + // find VT number using /dev/console + if (!ret) { + fd = xopen("/dev/console", O_RDONLY | O_NONBLOCK); + xioctl(fd, VT_GETSTATE, &vstate); + xvtnum(fd); + } + } + + sprintf(toybuf, "/dev/tty%lu", TT.vt_num); + fd = find_console_fd(); + xioctl(fd, VT_GETSTATE, &vstate); + + close(0); //new vt becomes stdin + vt_fd = xopen(toybuf, O_RDWR); + if (toys.optflags & FLAG_s) { + ioctl(vt_fd, VT_ACTIVATE, TT.vt_num); + ioctl(vt_fd, VT_WAITACTIVE, TT.vt_num); + } + + close(1); + close(2); + dup2(vt_fd, 1); + dup2(vt_fd, 2); + while (vt_fd > 2) + close(vt_fd--); + + pid = vfork(); + if (pid < 0) perror_exit("Fork failed"); + else if (!pid) { + setsid(); + ioctl(vt_fd, TIOCSCTTY, 0); + xexec(toys.optargs); + } + + if (toys.optflags & FLAG_w) { + while (-1 == waitpid(pid, NULL, 0) && errno == EINTR) + ; + if (toys.optflags & FLAG_s) { + ioctl(fd, VT_ACTIVATE, vstate.v_active); + ioctl(fd, VT_WAITACTIVE, vstate.v_active); + //check why deallocate isn't working here + xioctl(fd, VT_DISALLOCATE, (void *)(ptrdiff_t)TT.vt_num); + } + } +} |