toybox/toys/pending/openvt.c
<<
>>
Prefs
   1/* openvt.c - Run a program on a new VT
   2 *
   3 * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
   4 *
   5 * No Standard
   6
   7USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
   8USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
   9
  10config OPENVT
  11  bool "openvt"
  12  default n
  13  depends on TOYBOX_FORK
  14  help
  15    usage: openvt [-c N] [-sw] [command [command_options]]
  16
  17    start a program on a new virtual terminal (VT)
  18
  19    -c N  Use VT N
  20    -s    Switch to new VT
  21    -w    Wait for command to exit
  22
  23    if -sw used together, switch back to originating VT when command completes
  24
  25config DEALLOCVT
  26  bool "deallocvt"
  27  default n
  28  help
  29    usage: deallocvt [N]
  30
  31    Deallocate unused virtual terminal /dev/ttyN, or all unused consoles.
  32*/
  33
  34#define FOR_openvt
  35#include "toys.h"
  36#include <linux/vt.h>
  37#include <linux/kd.h>
  38
  39GLOBALS(
  40  unsigned long vt_num;
  41)
  42
  43int open_console(void)
  44{
  45  char arg, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
  46  int i, fd;
  47
  48  for (i = 0; i < ARRAY_LEN(console_name); i++) {
  49    fd = open(console_name[i], O_RDWR);
  50    if (fd >= 0) {
  51      arg = 0;
  52      if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
  53      close(fd);
  54    }
  55  }
  56
  57  /* check std fd 0, 1 and 2 */
  58  for (fd = 0; fd < 3; fd++) {
  59    arg = 0;
  60    if (0 == ioctl(fd, KDGKBTYPE, &arg)) return fd;
  61  }
  62
  63  return -1;
  64}
  65
  66int xvtnum(int fd)
  67{
  68  int ret;
  69
  70  ret = ioctl(fd, VT_OPENQRY, (int *)&TT.vt_num);
  71  if (ret != 0 || TT.vt_num <= 0) perror_exit("can't find open VT");
  72
  73  return TT.vt_num;
  74}
  75
  76void openvt_main(void)
  77{
  78  int fd, vt_fd, ret = 0;
  79  struct vt_stat vstate;
  80  pid_t pid;
  81
  82  if (!(toys.optflags & FLAG_c)) {
  83    // check if fd 0,1 or 2 is already opened
  84    for (fd = 0; fd < 3; fd++)
  85      if (!ioctl(fd, VT_GETSTATE, &vstate)) {
  86        ret = xvtnum(fd);
  87        break;
  88      }
  89
  90    // find VT number using /dev/console
  91    if (!ret) {
  92      fd = xopen("/dev/console", O_RDONLY | O_NONBLOCK);
  93      xioctl(fd, VT_GETSTATE, &vstate);
  94      xvtnum(fd);
  95    }
  96  }
  97
  98  sprintf(toybuf, "/dev/tty%lu", TT.vt_num);
  99  fd = open_console();
 100  xioctl(fd, VT_GETSTATE, &vstate);
 101
 102  close(0);  //new vt becomes stdin
 103  vt_fd = xopen_stdio(toybuf, O_RDWR);
 104  if (toys.optflags & FLAG_s) {
 105    ioctl(vt_fd, VT_ACTIVATE, TT.vt_num);
 106    ioctl(vt_fd, VT_WAITACTIVE, TT.vt_num);
 107  }
 108
 109  close(1);
 110  close(2);
 111  dup2(vt_fd, 1);
 112  dup2(vt_fd, 2);
 113  while (vt_fd > 2)
 114    close(vt_fd--);
 115
 116  pid = xfork();
 117  if (!pid) {
 118    setsid();
 119    ioctl(vt_fd, TIOCSCTTY, 0);
 120    xexec(toys.optargs);
 121  }
 122
 123  if (toys.optflags & FLAG_w) {
 124    while (-1 == waitpid(pid, NULL, 0) && errno == EINTR)
 125      ;
 126    if (toys.optflags & FLAG_s) {
 127      ioctl(fd, VT_ACTIVATE, vstate.v_active);
 128      ioctl(fd, VT_WAITACTIVE, vstate.v_active);
 129      //check why deallocate isn't working here
 130      xioctl(fd, VT_DISALLOCATE, (void *)(ptrdiff_t)TT.vt_num); 
 131    }
 132  }
 133}
 134
 135void deallocvt_main(void)
 136{
 137  long vt_num = 0; // 0 deallocates all unused consoles
 138  int fd;
 139
 140  if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
 141
 142  if ((fd = open_console()) < 0) error_exit("can't open console");
 143  xioctl(fd, VT_DISALLOCATE, (void *)vt_num);
 144  if (CFG_TOYBOX_FREE) close(fd);
 145}
 146