Created
July 28, 2019 15:39
-
-
Save dimitry-ishenko/af80e01d9303d85c89c1dae07a438558 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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