2016-01-16 5 views
3

Следующий код может действовать так, как ожидалось, если он выполняется оболочкой.чтение из stdin после execl() bash return eio (ошибка ввода/вывода)

Но если установить эту программу в качестве оболочки пользователя и SSH в хозяин, чтобы выполнить эту программу в качестве оболочки, то read(0, &buf123, 1); возвратит (/ ошибку выхода Input) 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 +++ 

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

+0

Итак, вы выполняете * интерактивную * оболочку и, параллельно, чтение со стандартного ввода, которое интерактивная оболочка также использует для чтения команд оболочки? Я подозреваю, что оболочка или readline помещают дескриптор файла в режим, который не позволяет ему делиться, пока оболочка ждет ввода. Это можно проверить, прервав оболочку и проанализировав, что она делает с fd 0. (Было бы также интересно проверить, почему одна и та же операция не возникает или не вызывает проблемы, когда программа запускается из уже запущенная оболочка.) – user4815162342

+0

EIO может быть возвращен вместо EOF, если fd ссылается на tty в Linux, [пример кода] (http://stackoverflow.com/a/12471855/4279). – jfs

+0

Очень благодарен за ваши ответы. У меня есть решение через ответ Жана-Батиста. – user2828102

ответ

2

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

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

Подробнее о группе терминалов POSIX, сессиях и процессах.

+2

Я просмотрел эти материалы в apue и нашел эту страницу http://www.gnu.org/software/libc/manual/html_node/Initializing-the-Shell.html. Большое спасибо. – user2828102