145 lines
3.1 KiB
C
145 lines
3.1 KiB
C
/* openvt.c - Run a program on a new VT
|
|
*
|
|
* Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
|
|
*
|
|
* No Standard
|
|
|
|
USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
|
|
USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
|
|
|
|
config OPENVT
|
|
bool "openvt"
|
|
default n
|
|
depends on TOYBOX_FORK
|
|
help
|
|
usage: openvt [-c N] [-sw] [command [command_options]]
|
|
|
|
start a program on a new virtual terminal (VT)
|
|
|
|
-c N Use VT N
|
|
-s Switch to new VT
|
|
-w Wait for command to exit
|
|
|
|
if -sw used together, switch back to originating VT when command completes
|
|
|
|
config DEALLOCVT
|
|
bool "deallocvt"
|
|
default n
|
|
help
|
|
usage: deallocvt [N]
|
|
|
|
Deallocate unused virtual terminal /dev/ttyN, or all unused consoles.
|
|
*/
|
|
|
|
#define FOR_openvt
|
|
#include "toys.h"
|
|
#include <linux/vt.h>
|
|
#include <linux/kd.h>
|
|
|
|
GLOBALS(
|
|
unsigned long vt_num;
|
|
)
|
|
|
|
int open_console(void)
|
|
{
|
|
char arg, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
|
|
int i, fd;
|
|
|
|
for (i = 0; i < ARRAY_LEN(console_name); i++) {
|
|
fd = open(console_name[i], O_RDWR);
|
|
if (fd >= 0) {
|
|
arg = 0;
|
|
if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
/* check std fd 0, 1 and 2 */
|
|
for (fd = 0; fd < 3; fd++) {
|
|
arg = 0;
|
|
if (0 == ioctl(fd, KDGKBTYPE, &arg)) return fd;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int xvtnum(int fd)
|
|
{
|
|
int ret;
|
|
|
|
ret = ioctl(fd, VT_OPENQRY, (int *)&TT.vt_num);
|
|
if (ret != 0 || TT.vt_num <= 0) perror_exit("can't find open VT");
|
|
|
|
return TT.vt_num;
|
|
}
|
|
|
|
void openvt_main(void)
|
|
{
|
|
int fd, vt_fd, ret = 0;
|
|
struct vt_stat vstate;
|
|
pid_t pid;
|
|
|
|
if (!(toys.optflags & FLAG_c)) {
|
|
// check if fd 0,1 or 2 is already opened
|
|
for (fd = 0; fd < 3; fd++)
|
|
if (!ioctl(fd, VT_GETSTATE, &vstate)) {
|
|
ret = xvtnum(fd);
|
|
break;
|
|
}
|
|
|
|
// find VT number using /dev/console
|
|
if (!ret) {
|
|
fd = xopen("/dev/console", O_RDONLY | O_NONBLOCK);
|
|
xioctl(fd, VT_GETSTATE, &vstate);
|
|
xvtnum(fd);
|
|
}
|
|
}
|
|
|
|
sprintf(toybuf, "/dev/tty%lu", TT.vt_num);
|
|
fd = open_console();
|
|
xioctl(fd, VT_GETSTATE, &vstate);
|
|
|
|
close(0); //new vt becomes stdin
|
|
vt_fd = xopen_stdio(toybuf, O_RDWR);
|
|
if (toys.optflags & FLAG_s) {
|
|
ioctl(vt_fd, VT_ACTIVATE, TT.vt_num);
|
|
ioctl(vt_fd, VT_WAITACTIVE, TT.vt_num);
|
|
}
|
|
|
|
close(1);
|
|
close(2);
|
|
dup2(vt_fd, 1);
|
|
dup2(vt_fd, 2);
|
|
while (vt_fd > 2)
|
|
close(vt_fd--);
|
|
|
|
pid = xfork();
|
|
if (!pid) {
|
|
setsid();
|
|
ioctl(vt_fd, TIOCSCTTY, 0);
|
|
xexec(toys.optargs);
|
|
}
|
|
|
|
if (toys.optflags & FLAG_w) {
|
|
while (-1 == waitpid(pid, NULL, 0) && errno == EINTR)
|
|
;
|
|
if (toys.optflags & FLAG_s) {
|
|
ioctl(fd, VT_ACTIVATE, vstate.v_active);
|
|
ioctl(fd, VT_WAITACTIVE, vstate.v_active);
|
|
//check why deallocate isn't working here
|
|
xioctl(fd, VT_DISALLOCATE, (void *)(ptrdiff_t)TT.vt_num);
|
|
}
|
|
}
|
|
}
|
|
|
|
void deallocvt_main(void)
|
|
{
|
|
long vt_num = 0; // 0 deallocates all unused consoles
|
|
int fd;
|
|
|
|
if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
|
|
|
|
if ((fd = open_console()) < 0) error_exit("can't open console");
|
|
xioctl(fd, VT_DISALLOCATE, (void *)vt_num);
|
|
if (CFG_TOYBOX_FREE) close(fd);
|
|
}
|