bash子进程ssh登录提示符异常输出至控制终端问题求助
问题分析与解决方法
核心原因
ssh的密码提示并没有通过bash的标准输出/错误输出传递,而是直接打开当前会话的控制终端(/dev/tty)写入——这是ssh为保证密码输入安全性,刻意绕过管道、重定向等中间层的设计。你的程序只接管了bash的PTY标准IO,但未修改子进程的控制终端归属,所以ssh直接把提示输出到了运行./TVI.out的原控制终端,跳过了你的转义转换逻辑。
针对性解决方案
1. 将PTY从设备设为子进程的控制终端
这是最直接的解决方法,让ssh认为你创建的PTY是它的控制终端,从而把密码提示输出到PTY中,进入你的处理流程:
在fork后的子进程、调用execlp("bash", "bash", NULL)之前,添加以下代码:
// 创建新会话,脱离原控制终端 if (setsid() == -1) { perror("setsid failed"); exit(EXIT_FAILURE); } // 将PTY从设备设置为当前会话的控制终端 if (ioctl(pty_slave, TIOCSCTTY, NULL) == -1) { perror("TIOCSCTTY failed"); exit(EXIT_FAILURE); } // 确保子进程的标准IO都绑定到PTY从设备 dup2(pty_slave, STDIN_FILENO); dup2(pty_slave, STDOUT_FILENO); dup2(pty_slave, STDERR_FILENO); if (pty_slave > STDERR_FILENO) { close(pty_slave); }
处理后,ssh会将密码提示写入PTY从设备,父进程就能捕获到输出并进行转义转换,最终显示在Televideo 910终端上。
2. 补充信号处理细节
你遇到的SIGTTOU信号是子进程尝试访问原控制终端时触发的(后台进程写控制终端会收到该信号),但仅忽略信号没用——必须让子进程不再依赖原控制终端,上面的控制终端切换操作才是根本解决方法,信号处理可作为辅助:
// 在父进程中设置信号处理(子进程会继承,setsid后会话改变,信号行为也会变化) signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN);
额外排查点
- 确认
openpty返回的主/从设备描述符正确,未被意外关闭。 - 检查父进程的PTY主设备读写逻辑是否覆盖所有输出场景(比如是否用
select/poll处理异步IO,监听所有可能的输出事件)。
内容的提问来源于stack exchange,提问作者Gregory
相关产品推荐
相关产品推荐

