The following code can act as expected if executed by a shell.
But if I set this program as a user’s shell and ssh into the host to execute this program as a shell, the read(0, &buf123, 1);
will return an EIO(Input/output error):
#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);
}
But if a change execl(bash)
into non-interactive bash execl(bash -c "id")
or other program rather than bash, the read(0, &buf123, 1);
will success.
So to reproduce this error, two conditions need to be met:
1. execvl() an interactive bash(system() can also reproduce this error)
2. run as a user's shell using ssh
Could anyone help me figure out why and how to avoid this?
The following is the strace
result:
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, "::Xv37(315177::n", 11) = 11
exit_group(11) = ?
+++ exited with 11 +++
Thanks in advance!
Advertisement
Answer
I happens because your sub-shell is a login interactive shell and so it took control over the terminal (set it as a its session control terminal). Then your process is disconnected from the terminal and cannot read on it anymore.
Of course if you use a non interactive shell, it don’t need the control over the terminal leaving it as is for your process.
Read about POSIX Terminal, sessions and processes group.