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   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 
     25 config 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 
     39 GLOBALS(
     40   unsigned long vt_num;
     41 )
     42 
     43 int 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 
     66 int 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 
     76 void 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 
    135 void 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