xref: /aosp_15_r20/external/toybox/toys/other/openvt.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* openvt.c - Run a program on a new VT
2  *
3  * Copyright 2008 David Anders <[email protected]>
4  * Copyright 2014 Vivek Kumar Bhagat <[email protected]>
5  *
6  * No Standard
7 
8 USE_OPENVT(NEWTOY(openvt, "^<1c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
9 USE_CHVT(NEWTOY(chvt, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
10 USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
11 
12 config OPENVT
13   bool "openvt"
14   default y
15   help
16     usage: openvt [-c NUM] [-sw] COMMAND...
17 
18     Run COMMAND on a new virtual terminal.
19 
20     -c NUM  Use VT NUM
21     -s    Switch to the new VT
22     -w    Wait for command to exit (with -s, deallocates VT on exit)
23 
24 config CHVT
25   bool "chvt"
26   default y
27   help
28     usage: chvt NUM
29 
30     Change to virtual terminal number NUM. (This only works in text mode.)
31 
32     Virtual terminals are the Linux VGA text mode (or framebuffer) displays,
33     switched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch
34     from X11 to a virtual terminal, and alt-F6 (or F7, or F8) to get back.
35 
36 config DEALLOCVT
37   bool "deallocvt"
38   default y
39   help
40     usage: deallocvt [NUM]
41 
42     Deallocate unused virtual terminals, either a specific /dev/ttyNUM, or all.
43 */
44 
45 #define FOR_openvt
46 #include "toys.h"
47 #include <linux/vt.h>
48 #include <linux/kd.h>
49 
GLOBALS(long c;)50 GLOBALS(
51   long c;
52 )
53 
54 static int open_console(void)
55 {
56   char arg = 0, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
57   int i, fd;
58 
59   for (i = 0; i < ARRAY_LEN(console_name); i++) {
60     if (0>(fd = open(console_name[i], O_RDWR))) continue;
61     if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
62     close(fd);
63   }
64   for (fd = 0; fd < 3; fd++) if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
65   error_exit("can't open console");
66 }
67 
activate(int fd,int cc)68 static int activate(int fd, int cc)
69 {
70   return ioctl(fd, VT_ACTIVATE, cc) || ioctl(fd, VT_WAITACTIVE, cc);
71 }
72 
openvt_main(void)73 void openvt_main(void)
74 {
75   struct vt_stat vstate;
76   int fd, cc = (int)TT.c;
77   pid_t pid;
78 
79   // find current console
80   if (-1 == (ioctl(fd = open_console(), VT_GETSTATE, &vstate)) ||
81       (!cc && 0>=(cc = xioctl(fd, VT_OPENQRY, &fd))))
82     perror_exit("can't find open VT");
83 
84   sprintf(toybuf, "/dev/tty%d", cc);
85   if (!(pid = XVFORK())) {
86     close(0);  //new vt becomes stdin
87     dup2(dup2(xopen_stdio(toybuf, O_RDWR), 1), 2);
88     if (FLAG(s)) activate(0, cc);
89     setsid();
90     ioctl(0, TIOCSCTTY, 0);
91     if (fd>2) close(fd);
92     xexec(toys.optargs);
93   }
94   if (FLAG(w)) {
95     while (-1 == waitpid(pid, NULL, 0) && errno == EINTR) errno = 0;
96     if (FLAG(s)) {
97       activate(fd, vstate.v_active);
98       dprintf(2, "%d\n", ioctl(fd, VT_DISALLOCATE, cc));
99     }
100   }
101 }
102 
chvt_main(void)103 void chvt_main(void)
104 {
105   if (activate(open_console(), atoi(*toys.optargs)))
106     perror_exit_raw(*toys.optargs);
107 }
108 
deallocvt_main(void)109 void deallocvt_main(void)
110 {
111   int fd = open_console(), vt_num = 0; // 0 = all
112 
113   if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
114   if (-1 == ioctl(fd, VT_DISALLOCATE, vt_num)) perror_exit("%d", vt_num);
115 }
116