Чтение из stdin после execl() bash возвращает eio(ошибка ввода / вывода)

Следующий код может действовать, как ожидается, если выполняется оболочкой.

Но если я установлю эту программу как оболочку пользователя и ssh на хост, чтобы выполнить эту программу как оболочку, read(0, &buf123, 1); вернет EIO(ошибка ввода / вывода):

#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 +++

Заранее спасибо!

1 ответ

Решение

Это происходит потому, что ваша под-оболочка является интерактивной оболочкой для входа в систему, и поэтому она взяла под свой контроль терминал (установите его в качестве терминала управления сеансом). Тогда ваш процесс отключен от терминала и больше не может читать по нему.

Конечно, если вы используете неинтерактивную оболочку, ей не нужен контроль над терминалом, оставляя его как есть для вашего процесса.

Читайте о POSIX-терминале, сессиях и группе процессов.

Другие вопросы по тегам