3

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, "::Xv\37(\315\177::\n", 11)    = 11
exit_group(11)                          = ?
+++ exited with 11 +++

Thanks in advance!

user2828102
  • 125
  • 1
  • 12
  • So, you are executing an *interactive* shell and, in parallel, reading from standard input, which the interactive shell is also usingto read the shell commands? I suspect the shell or readline is putting the file descriptor in a mode that doesn't allow it being shared while the shell is waiting for input. This could be checked by stracing the shell and examining what it does to fd 0. (It would also be interesting to check why the same operation doesn't occur, or doesn't cause the issue, when the program is started from an already running shell.) – user4815162342 Jan 16 '16 at 10:13
  • EIO may be returned instead of EOF if fd refers to a tty on Linux, [code example](http://stackoverflow.com/a/12471855/4279). – jfs Jan 16 '16 at 13:16
  • Very appreciate for your replies. I've got a solution through Jean-Baptiste's answer. – user2828102 Jan 18 '16 at 08:42

1 Answers1

2

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.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • 2
    I've reviewed those content in apue and found this page http://www.gnu.org/software/libc/manual/html_node/Initializing-the-Shell.html. Thanks a lot. – user2828102 Jan 17 '16 at 13:31