如何获得可运行'vi'等的分叉execve()
子进程,并将所有IO重定向到父进程?
我正在尝试将shell从嵌入式Linux进程传递到通过网络连接的PC软件接口。 shell进程的IO被打包到特定于应用程序的消息中,以便通过现有协议进行网络传输。
首先,我只是使用pipe2()
,fork()
,dup2()
和execve()
重定向IO。这并没有给我一个远程方面的tty,所以screen
等不起作用。
现在我正在使用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()
错误。我是否正确地认为这是一个控制性的问题?我该如何解决?
修改
小修正。当我在STDIN_FILENO上执行ioctl TIOCSCTTY时,它就像在上面的调试文件中那样工作,但IO重定向回到父进程中断。
编辑2
好的,我开始更好地理解这一点了。查看tcsetattr()后面的ioctl的内核源代码,我正在调用的进程在尝试更改tty时发送SIGTTIN和SIGTTOU。
只有前台进程可以执行此操作,并且它们正在运行,就好像它们是后台进程一样。我尝试在分叉之后和execve()之前将这些信号设置为SIG_IGN,但这不起作用。我理解这个语义,但是在我的重定向场景中,execve()进程就好像它们是前台进程一样安全。问题是......如何做到这一点?我将继续在内核代码中搜索线索。
答案 0 :(得分:1)
唉!这是bash,我用execve()调用的shell。
如果它检测到stderr没有附加到tty,那么它进入这种特殊模式,其中子进程导致SIGTTOU。
我发现了这个问题here.
当我停止将stderr重新定向远离tty时,它现在似乎按计划工作。