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.