我正在尝试编写一个 C 程序,该程序创建一个运行新 bash 实例的伪终端,并记录通过它的所有输入和输出。最终目标是将其异步发送到服务器,其他人可以实时查看您的终端活动。
我已经完成了伪术语创建步骤,我可以启动一个新的 bash 实例并记录"大部分"输入和输出。我现在的问题是伪术语无法正确识别箭头键。它们作为 ASCII 值(^[[A, ^[[[B, ^[[C, ^[[D)
打印到屏幕上,而不是在命令行周围移动光标。
这是 pty 的从属部分,它将运行 bash:
if(pid == 0){ //child
struct termios term_settings;
close(ptyfds.master);
rc = tcgetattr(ptyfds.slave, &term_settings);
cfmakeraw(&term_settings);
tcsetattr(ptyfds.slave, TCSANOW, &term_settings);
//replace stdin,out,err with the slave filedesc
close(0);
close(1);
close(2);
dup(ptyfds.slave);
dup(ptyfds.slave);
dup(ptyfds.slave);
//We can close original fd and use 0,1,2
close(ptyfds.slave);
//Make this process the session lead
setsid();
//Slave side of PTY becomes the new controlling terminal
ioctl(0, TIOCSCTTY, 1);
char ** child_argv = (char **) malloc(argc * sizeof(char*));
int i;
for(i=1; i<argc; i++){
child_argv[i-1] = strdup(argv[i]); //could be bash, bc, python
}
child_argv[i-1] = NULL;
rc = execvp(child_argv[0], child_argv);
}
这是pty的主站,向从站发送输入并捕获其输出。
if(pid == 0){ //parent
fd_set fd_in;
close(ptyfds.slave);
FILE *logFile = fopen("./log", "w");
while(1){
//Add stdin and master fd to object
FD_ZERO(&fd_in);
FD_SET(0,&fd_in);
FD_SET(ptyfds.master, &fd_in);
//intercept data from stdin or from slave out (which is redirected to master)
rc = select(ptyfds.master+1, &fd_in, NULL,NULL,NULL);
switch(rc){
case -1:
fprintf(stderr, "Error %d on select()n", errno);
exit(1);
default:
if (FD_ISSET(0, &fd_in)){ //There's data on stdin
rc = read(0, input, sizeof(input));
if(rc > 0){
input[rc] = ' ';
write(ptyfds.master, input, rc);//send to master -> slave
fputs(input, logFile);
}
else if(rc < 0){
fprintf(stderr, "Error %d on stdinn", errno);
exit(1);
}
}
if(FD_ISSET(ptyfds.master, &fd_in)){ //There's data from slave
rc = read(ptyfds.master, input, sizeof(input)-1);
if(rc > 0){
input[rc] = ' ';
write(1, input, rc);//send to stdout
fputs(input, logFile);
}
else if (rc < 0){
fprintf(stderr, "Error %d on read master ptyn", errno);
exit(1);
}
}
}//switch
}//while
}//end parent
我尝试在这里弄乱 termios 标志,但没有一个指定箭头键。
我需要做什么?
其中大部分代码来自这里。
我认为示例程序中有一个错误。 我能够通过移动来修复它:
rc = tcgetattr(ptyfds.slave, &term_settings);
cfmakeraw(&term_settings);
tcsetattr(ptyfds.slave, TCSANOW, &term_settings);
进入主部分并将ptyfds.slave
替换为STDIN_FILENO
(这会将 STDIN 设置为原始模式,而不是从模式(