Linux下如何将Slave设为控制终端?ioctl调用失败排查修复
问题:PTY Slave设置控制终端失败排查与修复
我在Linux环境中编写代码尝试将PTY Slave设置为控制终端,但调用
ioctl(TIOCSCTTY)失败。连接远程服务器成功后出现如下错误:bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell进程能正常运行,但控制终端未成功设置,检查发现程序运行前后控制终端均为
/dev/pty/7。代码示例如下:int main(int argc, char ** argv) { int master, slave, status; int client_socket; /* created the socket and connected to the remote server */ pid_t pid = fork(); if (pid < 0) { perror("Failed to fork process"); } else if (pid == 0) { close(master); if (openpty(&master, &slave, slave_name, NULL,NULL) != 0) { perror("child process failed to create a pty"); } if (setsid() < 0) { perror("failed to start new session"); } if (ioctl(slave, TIOCSCTTY, 0) < 0) { perror("failed set to slave as controlling tty"); } execl("/bin/bash", "/bin/bash", NULL); } else { close(slave); // PARENT waitpid(pid, &status, 0); } close(client_socket); return 0; }
原因分析
- 子进程继承了父进程的控制终端:fork后的子进程会沿用父进程的控制终端
/dev/pty/7,而TIOCSCTTY要求调用进程所在的会话没有控制终端,否则调用直接失败。 - 标准流未关联PTY Slave:bash启动后默认使用继承的标准输入/输出/错误,没有绑定到新创建的Slave端,导致bash无法识别该PTY为控制终端。
- 逻辑混淆与错误处理缺失:子进程先关闭master再调用
openpty重新赋值,变量逻辑混乱;且未处理openpty、setsid等调用失败后的退出逻辑,可能导致后续代码无效执行。
修复方案
关键修复步骤
- 关闭子进程继承的标准流,确保脱离父进程的控制终端;
- 调用
setsid创建新会话,成为无控制终端的会话首进程; - 将标准输入/输出/错误重定向到PTY Slave;
- 完善错误处理,确保调用失败时及时退出;
- 启动交互式bash(加
-i参数),保障job control正常工作。
修复后的代码
#include <stdlib.h> #include <unistd.h> #include <pty.h> #include <sys/ioctl.h> #include <sys/wait.h> #include <stdio.h> int main(int argc, char ** argv) { int master, slave, status; int client_socket; char slave_name[256]; /* created the socket and connected to the remote server */ pid_t pid = fork(); if (pid < 0) { perror("Failed to fork process"); exit(EXIT_FAILURE); } else if (pid == 0) { // 关闭父进程传递的master描述符 close(master); // 创建PTY设备 if (openpty(&master, &slave, slave_name, NULL, NULL) != 0) { perror("child process failed to create a pty"); exit(EXIT_FAILURE); } // 关闭继承的标准流,脱离父进程控制终端 close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); // 创建新会话,成为会话首进程(此时无控制终端) if (setsid() < 0) { perror("failed to start new session"); exit(EXIT_FAILURE); } // 将PTY Slave设置为当前会话的控制终端 if (ioctl(slave, TIOCSCTTY, 0) < 0) { perror("failed set to slave as controlling tty"); exit(EXIT_FAILURE); } // 重定向标准流到PTY Slave dup2(slave, STDIN_FILENO); dup2(slave, STDOUT_FILENO); dup2(slave, STDERR_FILENO); // 关闭多余的Slave和Master描述符 close(slave); close(master); // 启动交互式bash,确保job control正常 execl("/bin/bash", "/bin/bash", "-i", NULL); // execl执行失败时的处理 perror("execl failed"); exit(EXIT_FAILURE); } else { close(slave); // 父进程可在此处理master与client_socket的交互逻辑 waitpid(pid, &status, 0); } close(client_socket); return 0; }
修复效果说明
- 子进程通过关闭标准流+
setsid,确保会话无控制终端,此时TIOCSCTTY调用会成功; - 标准流重定向后,bash的输入输出完全绑定到新PTY,会自动识别其为控制终端;
- 交互式bash(
-i)会启用job control,解决报错中的"no job control in this shell"问题。
内容的提问来源于stack exchange,提问作者RAT
相关产品推荐
相关产品推荐

