Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将所有用户输入转发到子进程中的Linux PTY_C_Linux_Tty_Pty - Fatal编程技术网

C 将所有用户输入转发到子进程中的Linux PTY

C 将所有用户输入转发到子进程中的Linux PTY,c,linux,tty,pty,C,Linux,Tty,Pty,背景 我正在尝试为shell构建一个包装器。它在TTY中运行,通过在子进程中生成常规shell。其目的是将所有用户输入按原样转发到子进程,但在将其复制到父进程“stderr”之前拦截子进程的输出并对其进行一些处理。用户应该能够忘记,除了增加的输出之外,shell是被包装的 问题 我不知道如何透明地转发输入。下面是我当前代码的要点(错误检查和次要细节省略)。它应该使用gcc-pthread-lutil编译: #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #

背景

我正在尝试为shell构建一个包装器。它在TTY中运行,通过在子进程中生成常规shell。其目的是将所有用户输入按原样转发到子进程,但在将其复制到父进程“
stderr
”之前拦截子进程的输出并对其进行一些处理。用户应该能够忘记,除了增加的输出之外,shell是被包装的

问题

我不知道如何透明地转发输入。下面是我当前代码的要点(错误检查和次要细节省略)。它应该使用gcc-pthread-lutil编译:

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义BUF_大小512
#定义EOT“\x04”//ASCII传输结束(即“EOF”)。
void*tty_输入_例程(void*arg);
无效tty_输出_例程();
int parent_term_fd;
挥发性sig_原子的got_sigchld=0;
易失性sig_原子t get_sigwinch=0;
//侦听子级退出,并使父级退出。
无效句柄符号(int sig){
got_sigchld=1;
}
//侦听要调整大小的父对象,并使子对象调整大小。
无效手柄(内部信号){
got_sigwinch=1;
}
void main(){
/*阻塞SIGHWINCH和SIGCHLD。它们随后通过主回路中的pselect解锁*/
sigset_t sigsmask;
SIGEPTYSET(&sigmask);
sigaddset(&sigmask,SIGWINCH);
sigaddset(&sigmask,SIGCHLD);
sigprocmask(SIG_块和sigmask,NULL);
/*建立信号处理器*/
结构sig动作sig_动作;
sig_action.sa_flags=0;
sig_action.sa_handler=&handle_sigchld;
sig清空设置(&sig_action.sa_mask);
SIGCHLD和sig_动作,空;
sig_action.sa_handler=&handle_sigwinch;
sigaction(SIGWINCH和sig_动作,NULL);
/*获取初始终端大小*/
结构winsize项_sz;
ioctl(标准文件号、TIOCGWINSZ和term_sz);
/*关闭子终端中的输入回显,因为父终端应该这样做*/
结构术语;
tcgetattr(标准文件号和术语);
术语ios.c\u lflag&=~(ECHO);
/*用叉子叉*/
pid_t child_pid=forkpty(&parent_term_fd,NULL,&term_ios,&term_sz);
如果(子项pid==0){
/*这是子进程。执行shell*/
char*const argv[]={NULL};
execvp(“/bin/bash”,argv);
}
/*这是父进程。
*生成一个专用线程,将输入转发到子PTY。
*主线程将用于处理输出*/
pthread_t input_thread;
pthread_create(&input_thread,NULL,&tty_input_例程,NULL);
tty_输出_例程(父项_项_fd);
}
void*tty_输入_例程(void*arg){
结构termios tcattr;
tcgetattr(标准文件号和tcattr);
//cfmakeraw(&tcattr);//这似乎没有帮助。
//tcattr.c\u lflag&=~ICANON;//这也不是。。。
tcsetattr(标准文件号、TCSAFLUSH和tcattr);
字符大小[buf_SIZE];
fd_集fds;
FD_零(&fds);
while(true){
FD_集(标准文件号和fds);
如果(选择(标准文件号+1,&fds,NULL,NULL,NULL)=-1){
如果(errno==EINTR){
继续;//捕获到信号;请重试。
}
//否则,会出现一些错误。。。
看跌期权(“这是出乎意料的”);
打破
}否则{
ssize_t bytes=读取(标准文件号、buf、buf_大小);
如果(字节>0){
写入(父项fd,buf,(大小)字节);
}else if(字节==0){
/*传输结束*/
写入(父项fd,EOT,1);
打破
}
}
}
返回NULL;
}
无效tty_输出_例程(){
fd_集fds;
FD_零(&fds);
sigset_u u t empty_sigmask;
signemptyset(&empty_sigmask);
字符大小[buf_SIZE];
while(true){
FD_集(父项_项_FD和fds);
if(pselect(父项\u项\u fd+1,&fds,NULL,NULL,NULL,&empty\u sigmask)=-1){
如果(errno==EINTR){
/*信号被捕捉到了*/
如果(得到信号){
got_=0;
结构winsize项_sz;
ioctl(标准文件号、TIOCGWINSZ和term_sz);
/*这会给孩子发信号*/
ioctl(父项、术语、fd、TIOCSWINSZ和术语);
}
如果(得到信号){
//当用户按CTRL+D组合键,但它不。。。
puts(“这是正确的出口”);
返回;
}
}否则{
//否则,会出现一些错误。。。
打破
}
}否则{
ssize_t bytes=读取(父项、子项、子项大小);
//(省略)对缓冲区进行一些处理。
写入(标准文件号,buf,(大小)字节);
}
}
}
  • 其思想是,当用户点击
    CTRL+D
    时,输入例程将读取一个空缓冲区,并将
    EOT
    发送给子级,子级将退出,导致父级触发
    SIGCHLD
    ,父级也将退出。但是,
    SIGCHLD
    从未在父级中引发,即使它将
    exit
    打印到屏幕上这一事实表明,
    bash
    肯定会退出。令人困惑的是,
    SIGWINCH
    似乎处理得很好

  • 此外,父级无法将
    CTRL+C
    转发给子级。即使我为
    SIGTERM
    添加了另一个信号处理程序,并简单地通过
    kill
    将该信号转发给子级,shell本身也会退出,而不是像bash通常那样在shell中运行的任何东西。我是