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 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