• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
GLOBALS(unsigned long vt_num;)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 
xvtnum(int fd)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 
openvt_main(void)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 
deallocvt_main(void)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