execve_hook/tests/forkpty.c

130 lines
3.2 KiB
C

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <pty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
volatile sig_atomic_t terminate = 0;
void sig_handler(int sig) {
terminate = 1;
}
void createDup() {
int master_fd;
pid_t pid;
signal(SIGINT, sig_handler);
signal(SIGCHLD, sig_handler);
pid = forkpty(&master_fd, NULL, NULL, NULL);
if (pid < 0) {
perror("forkpty");
exit(EXIT_FAILURE);
}
if (pid == 0) {
// 子进程设置:如果父进程退出,自动收到 SIGTERM
prctl(PR_SET_PDEATHSIG, SIGTERM);
return;
} else {
char buffer[1024];
ssize_t num_read;
int output_fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (output_fd < 0) {
perror("open output.txt");
exit(EXIT_FAILURE);
}
fd_set read_fds;
int max_fd = (STDIN_FILENO > master_fd ? STDIN_FILENO : master_fd) + 1;
while (!terminate) {
FD_ZERO(&read_fds);
FD_SET(STDIN_FILENO, &read_fds);
FD_SET(master_fd, &read_fds);
int ret = select(max_fd, &read_fds, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR) {
perror("select");
break;
}
if (terminate) break;
// 用户输入
if (FD_ISSET(STDIN_FILENO, &read_fds)) {
num_read = read(STDIN_FILENO, buffer, sizeof(buffer));
if (num_read <= 0) break;
write(master_fd, buffer, num_read);
}
// 子进程输出
if (FD_ISSET(master_fd, &read_fds)) {
num_read = read(master_fd, buffer, sizeof(buffer));
if (num_read <= 0) break;
write(STDOUT_FILENO, buffer, num_read);
write(output_fd, buffer, num_read);
}
}
kill(pid, SIGTERM); // 通知子进程退出
waitpid(pid, NULL, 0);
close(output_fd);
close(master_fd);
exit(EXIT_SUCCESS);
}
}
int main() {
createDup();
signal(SIGINT, sig_handler);
pid_t pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程确保在父进程退出时自动结束
prctl(PR_SET_PDEATHSIG, SIGTERM);
printf("This is the child process.\n");
fflush(stdout);
} else {
printf("This is the parent process.\n");
fflush(stdout);
}
// 测试输入
char input[100];
printf("Enter something: ");
fflush(stdout);
if (fgets(input, sizeof(input), stdin) == NULL) exit(0);
printf("You entered: %s", input);
fflush(stdout);
// 测试输出
printf("This is a test output.\n");
fflush(stdout);
// 测试错误输出
fprintf(stderr, "This is a test error output.\n");
fflush(stderr);
char *const argv[] = {"bash", NULL, NULL};
extern char **environ;
execve("/usr/bin/bash", argv, environ);
return 0;
}