我有一個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