我有一个Linux进程在后台运行。我想通过SSH接管它的stdin/out/err,并且也是终端控制器。 “原始”文件描述符也是伪终端。 我试过Reptyr和dupx。 Reptyr在vfork周围失败,但dupx工作得很好。所述GDB脚本它产生:控制终端和GDB
attach 123
set $fd=open("/dev/pts/14", 0)
set $xd=dup(0)
call dup2($fd, 0)
call close($fd)
call close($xd)
set $fd=open("/dev/pts/14", 1089)
set $xd=dup(1)
call dup2($fd, 1)
call close($fd)
call write($xd, "Remaining standard output of 123 is redirected to /dev/pts/14\n", 62)
call close($xd)
set $fd=open("/dev/pts/14", 1089)
set $xd=dup(2)
call dup2($fd, 2)
call close($fd)
call write($xd, "Remaining standard error of 123 is redircted to /dev/pts/14\n", 60)
call close($xd)
只要dupx命令完成时,不返回壳和目标应用程序接收我的输入(经由PTS/14)立即。
现在我想用我的独立二进制应用程序来实现相同的结果。我已经移植了相同的系统调用(DUP/DUP2 /关闭等)由dupx驱动什么被脚本由GDB执行:
int fd; int xd;
char* s = "Remaining standard output is redirected to new terminal\n";
fd = open(argv[1], O_RDONLY);
xd = dup(STDIN_FILENO);
dup2(fd, STDIN_FILENO);
close(fd);
close(xd);
fd = open(argv[1], O_WRONLY|O_CREAT|O_APPEND);
xd = dup(STDOUT_FILENO);
dup2(fd, STDOUT_FILENO);
close(fd);
write(xd, s, strlen(s));
close(xd);
fd = open(argv[1], O_WRONLY|O_CREAT|O_APPEND);
xd = dup(STDERR_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
write(xd, s, strlen(s));
close(xd);
运行snipplet上述通过注入一个共享库到远程进程完成通过sigstop/ptrace attach/dlopen/etc(使用类似于hotpatch的工具)。让我们考虑这个问题的一部分是安全可靠的:完成所有这些之后,目标进程的文件描述符会根据需要进行更改。我可以通过简单地检查/ proc/pidof target
/fd来验证它。
但是,外壳返回,它仍然接收我的所有输入,而不是目标应用程序。
我注意到,如果我在这个点之后简单地用gdb连接/分离(=通过注入的C代码改变了fds)而没有实际改变任何东西,所需的行为就完成了(意思是:shell不返回,但目标应用程序启动接收我的输入)。命令是:
gdb --pid=`pidof target` --batch --ex=quit
现在我的问题是:如何?在后台发生了什么?如何在没有gdb的情况下做同样的事情?我已经尝试过使用stracing gdb来获取一些提示,并尝试使用tty ioctl API而没有任何运气。
请注意,通过fork/setsid方式获取终端控制器状态(如果这是所有问题的关键),Reptyr使用的方式对我来说是不可接受的:我想避免分叉。 此外,我无法控制启动目标,所以“为什么不在屏幕上运行它”在这里没有答案。
你写了_As一旦dupx命令完成,shell不会返回,目标应用程序立即收到我的输入(通过pts/14)._你从哪里得到这个'pts/14'?如果它是你的shell的终端,那么在'dupx'之后,shell和_target app_正在争夺来自'pts/14'的输入,而难以预测结果。 – Armali
我ssh访问,那是pts/14来自哪里。壳牌和目标应用可能会竞争,但我从来没有经历过这种行为; dupx在这种情况下做了我想要的。 – Saturnus