view toys/pending/openvt.c @ 1214:a31d747b0017 draft

Please find the patches attached herewith for adding 3 new commands - 1. freeramdisk - If we unmount or detach the RAM disk based file system the Linux Kernel will not free the allocated memory associated with the RAM device. This can be useful if one wants to mount this device again: All data will be preserved. If we need to free the memory back to the Kernel, one can use the command: "toybox freeramdisk <RAM device>". 2. openvt - Successfully opens a new virtual terminal as mentioned with -c option otherwise search and open next available VT. with -s option it switches to new VT with -s -w option, it switch back successfully to originating VT. 3. deallocvt - Deallocate specified virtual teminal. if no virtual terminal is specified, it deallocates all unused VT.
author Vivek Bhagat <vivek.bhagat89@gmail.com>
date Sun, 09 Mar 2014 14:27:11 -0500
parents
children 3c855d5a75be
line wrap: on
line source

/* 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))

config OPENVT
  bool "openvt"
  default n
  help
    usage: openvt [-c N] [-s] [-w] [--] [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 -s and -w option used together, switch back
          to originating VT when command completes
*/

#define FOR_openvt
#include "toys.h"
#include <linux/vt.h>
#include <linux/kd.h>

GLOBALS(
	unsigned long vt_num;
)

int find_console_fd(void)
{
	char *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
	int i;
	int fd;
	char arg;

	for (i = 0; i < 3; i++) {
		fd = open(console_name[i], O_RDWR);
		if (fd < 0 && errno == EACCES)
			fd = open(console_name[i], O_RDONLY);

		if (fd < 0 && errno == EACCES)
			fd = open(console_name[i], O_WRONLY);

		if (fd >= 0) {
			arg = 0;
			if (0 == ioctl(fd, KDGKBTYPE, &arg))
				return fd;
			else
				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 = -1, vt_fd = -1, pid, ret = 0;
	struct vt_stat vstate;

	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 = find_console_fd();
	xioctl(fd, VT_GETSTATE, &vstate);

	close(0);	//new vt becomes stdin
	vt_fd = xopen(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 = vfork();
	if (pid < 0)	perror_exit("Fork failed");
	else 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); 
		}
	}
}