1 /* openvt.c - Run a program on a new VT 2 * 3 * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89 (at) 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 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 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 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 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