如何获得execve()
可以运行“vi”等的分叉子进程并将所有 IO 重定向到父进程?
我正在尝试将 shell 从嵌入式 Linux 进程传递到通过网络连接的 PC 软件接口。shell 进程的 IO 被打包到特定于应用程序的消息中,以便通过我们现有的协议进行网络传输。
首先,我只是简单地使用pipe2()
、fork()
、dup2()
和重定向 IO execve()
。这在远程端没有给我一个 tty,所以screen
, etc. 没有用。
现在我正在使用forkpty
,并且screen
大部分都可以使用,但许多其他的却没有(vi
,stty
等)。看来当前的问题是子进程不控制 tty。
我一直在尝试 TIOCSCTTY,但运气不佳。
这或多或少是我所拥有的:
bool ExternalProcess::launch(...)
{
...
winsize winSize;
winSize.ws_col = 80;
winSize.ws_row = 25;
winSize.ws_xpixel = 10;
winSize.ws_ypixel = 10;
_pid = forkpty(&_stdin, NULL, NULL, &winSize);
//ioctl(_stdin, TIOCNOTTY, NULL);
if (!_pid && (_pid != -1))
{
// this is the child process
char tty[4096];
strncpy(tty, ttyname(STDIN_FILENO), sizeof(tty));
tty[sizeof(tty)-1]=0;
FILE* fp = fopen("debug.txt", "wt"); // no error checking - temporary test code
fprintf(fp, "slave TTY %s", tty);
//if (ioctl(_stdin, TIOCSCTTY, NULL) < 0)
if (ioctl(STDIN_FILENO, TIOCSCTTY, NULL) < 0)
{
fprintf(fp, "ioctl() TIOCSCTTY %s\n", strerror(errno));
fflush(fp);
}
else
{
fprintf(fp, "SET CONTROLLING TTY!");
fflush(fp);
}
fclose(fp);
// command, args, env populated elsewhere
execve(command, args, env);
...
// fail path
_exit(-1);
return false;
}
_stdout = _stdin;
...
// enter select() loop reading/writing _stdin, _stdout
}
我在调试文件中得到结果,例如:
slave TTY /dev/pts/5
SET CONTROLLING TTY!
但仍有许多应用程序因tcsetattr()
错误而失败。我是否认为这是一个控制 tty 问题?我如何解决它?
编辑
小修正。当我在 STDIN_FILENO 上执行 ioctl TIOCSCTTY 时,它就像在上面的调试文件中一样工作,但是返回父进程的 IO 重定向被中断。
编辑 2
好吧,我开始更好地理解这一点。查看 tcsetattr() 后面的 ioctl 的内核源代码,我正在调用的进程在尝试更改 tty 时被发送 SIGTTIN 和 SIGTTOU。
只有前台进程可以做到这一点,并且它们就像后台进程一样运行。我尝试在分叉之后和 execve() 之前将这些信号设置为 SIG_IGN,但这不起作用。我理解这个的语义,但是在我的重定向场景中,execve() 的进程就像它们是前台进程一样是安全的。问题是……如何做到这一点?我将继续在内核代码中寻找线索。