130 lines
3.2 KiB
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;
|
|
}
|