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