以下代码可以按预期执行,如果由shell执行。
但是,如果我把这个程序设置为一个用户的shell和ssh到主机来执行这个程序作为一个shell,那么read(0, &buf123, 1);
将返回一个EIO(input/输出错误):
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <regex.h> #include <curl/curl.h> #include <readline/readline.h> int main() { char *shell = "/bin/bash"; pid_t child; if ((child = fork()) < 0) { perror("vfork"); return; } if (child == 0) { execl(shell, shell + 5, "-c", "exec /bin/bash --login", NULL); perror("execl"); return; } wait(NULL); char buf123[1024]; read(0, &buf123, 1); printf("::%s::\n", buf123); }
但是,如果更改execl(bash)
到非交互式bash execl(bash -c "id")
或其他程序而不是bash, read(0, &buf123, 1);
会成功。
所以要重现这个错误,需要满足两个条件:
1. execvl() an interactive bash(system() can also reproduce this error) 2. run as a user's shell using ssh
任何人都可以帮我弄清楚为什么以及如何避免这种情况?
以下是strace
结果:
wait4(-1, NULL, 0, NULL) = 2 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2, si_status=0, si_utime=0, si_stime=0} --- read(0, 0x7fff7a4c8cb0, 1) = -1 EIO (Input/output error) fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcd281f3000 write(1, "::Xv\37(\315\177::\n", 11) = 11 exit_group(11) = ? +++ exited with 11 +++
提前致谢!
我碰巧是因为你的子shell是一个登录交互式shell,所以它控制了终端(把它设置为它的会话控制终端)。 然后你的进程从终端上断开,不能再读取了。
当然,如果您使用非交互式shell,则不需要对终端进行控制,而是将其保留为您的进程。
阅读有关POSIX终端,会话和进程组。