Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dimitry-ishenko
Created July 28, 2019 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dimitry-ishenko/af80e01d9303d85c89c1dae07a438558 to your computer and use it in GitHub Desktop.
Save dimitry-ishenko/af80e01d9303d85c89c1dae07a438558 to your computer and use it in GitHub Desktop.
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h> // PATH_MAX
#include <linux/vt.h> // VT_*
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strerror
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h> // TIO*
#include <unistd.h>
void die(const char* message)
{
fprintf(stderr, "%s - %s\n", message, strerror(errno));
exit(1);
}
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("Usage: chvt_exec <command> [args...]");
return 0;
}
int fd = open("/dev/console", O_RDWR);
if(fd < 0) die("Failed to open console");
struct vt_stat st;
if(ioctl(fd, VT_GETSTATE, &st) < 0) die("Failed to get active vt");
int vt = -1;
if(ioctl(fd, VT_OPENQRY, &vt) < 0) die("Failed to get free vt");
char vt_name[PATH_MAX + 1];
snprintf(vt_name, PATH_MAX, "/dev/tty%d", vt);
printf("Found free vt: %s\n", vt_name);
pid_t pid = fork();
if(pid == 0)
{
// child
if(setsid() < 0) die("Failed to create new session");
int fd_c = open(vt_name, O_RDWR);
if(fd_c < 0) die("Failed to open new vt");
if(ioctl(fd_c, TIOCSCTTY, 1) < 0) die("Failed to set controlling terminal");
if(ioctl(fd_c, VT_ACTIVATE, vt) < 0) die("Failed to activate new vt");
if(ioctl(fd_c, VT_WAITACTIVE, vt) < 0) die("Failed to wait for new vt to become active");
if(dup2(fd_c, 0) < 0 || dup2(fd_c, 1) < 0 || dup2(fd_c, 2) < 0)
die("Failed to redirect stdin, stdout or stderr to new vt");
close(fd);
execvp(argv[1], &argv[1]);
exit(1);
}
else if(pid < 0) die("Failed to fork child process");
// parent
int status = 0;
printf("Waiting for child process\n");
wait(NULL);
waitpid(pid, &status, 0);
if(ioctl(fd, VT_ACTIVATE, st.v_active) < 0) die("Failed to activate old vt");
if(ioctl(fd, VT_WAITACTIVE, st.v_active) < 0) die("Failed to wait for old vt to become active");
if(ioctl(fd, VT_DISALLOCATE, vt) < 0) die("Failed to deallocate new vt");
close(fd);
return status;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment