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 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
GLOBALS(unsigned long vt_num;)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
xvtnum(int fd)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
openvt_main(void)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
deallocvt_main(void)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