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