【发布时间】:2020-06-10 16:23:04
【问题描述】:
我有一个从管道(2)的手册页复制的程序,经过修改,子进程从 shell 分叉,父进程从标准输入读取,将命令发送到子 shell 以执行。这适用于第一个命令,但在运行该命令后,我收到一条消息,表明程序已停止并返回到顶级 shell。
为什么会发生这种情况,我该如何阻止它?
信号(7)说:
SIGTTIN P1990 Stop Terminal input for background process
但它不应该是后台进程,为什么它会停止?
接下来是带有完整源代码的终端会话,gcc -Wall 的结果,并尝试运行程序。如您所见,我给出命令“日期”,然后我被送回 到调用外壳,然后子外壳执行“日期”并出现输出,然后出现“退出”。 “fg”让我回到 pipe_shell 程序,“uptime”被发送到 shell 并运行,然后我可以做一个“echo”,然后我被送回顶级 shell,“exit”再次出现。
sh-5.0$ cat pipe_shell.c
/* pipe_shell.c - learn about pipes
*
* Modified from the man page for pipe(2).
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
if (argc != 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { // Child reads from pipe
close(pipefd[1]); // Close unused write end of pipe
close(STDIN_FILENO); // shut off standard input
dup2(pipefd[0], STDIN_FILENO); // pipe output is standard input
close(pipefd[0]); // close pipe output
execl("/bin/bash", "bash",
"--norc",
"-i",
(char *) 0);
perror("exec");
} else { // Parent writes to pipe
close(pipefd[0]); // Close unused read end
char line[256]; // we take input from keyboard
while ( fgets(line, 255, stdin) != NULL ) {
write(pipefd[1], line, strlen(line));
}
close(pipefd[1]); // Reader will see EOF
wait(NULL); // Wait for child
exit(EXIT_SUCCESS);
}
}
sh-5.0$ gcc -Wall pipe_shell.c -o pipe_shell
sh-5.0$ ./pipe_shell
bash-5.0$ date
date
[1]+ Stopped(SIGTTIN) ./pipe_shell
sh-5.0$ Wed 10 Jun 2020 12:16:28 PM EDT
bash-5.0$ exit
There are stopped jobs.
sh-5.0$ fg
./pipe_shell
uptime
uptime
12:16:52 up 154 days, 23:32, 5 users, load average: 0.04, 0.05, 0.07
bash-5.0$ echo "foo"
[1]+ Stopped(SIGTTIN) ./pipe_shell
echo "foo"
sh-5.0$ foo
bash-5.0$ exit
exit
【问题讨论】:
-
你读过advanced linux programming然后syscalls(2)和termios(3)和signal(7)和signal-safety(7)和pipe(7)吗?你研究过源代码吗? zsh ?
-
不,我继承了 12,000 行不太有效的代码,并被告知要修复它。我将问题追踪到一个执行类似操作的大块头,然后从手册页开始复制它。如果您能缩小我应该从哪里开始,我会非常乐意阅读所有这些内容。
-
12000 行很小。您可以使用GDB、strace(1)、ltrace(1) 和Clang analyzer 来了解它们。或许也写你自己的GCC plugin。预算几个月的工作。另请查看sash的源代码
-
但是 StackOverflow 不是一个做我的工作的网站。在您的下一个问题中提供一些minimal reproducible example。
-
这是一个最小的可重现示例,这就是我包含它的原因。