execve ("/ bin / sh", 0, 0);в трубе - PullRequest
       57

execve ("/ bin / sh", 0, 0);в трубе

10 голосов
/ 14 декабря 2011

У меня есть следующий пример программы:

#include <stdio.h>

int
main(int argc, char ** argv){
    char buf[100];

    printf("Please enter your name: ");
    fflush(stdout);
    gets(buf);
    printf("Hello \"%s\"\n", buf);

    execve("/bin/sh", 0, 0);
}

I, и когда я запускаю без какой-либо трубы, она работает как надо и возвращает sh Promt:

bash$ ./a.out
Please enter your name: warning: this program uses gets() which is unsafe.
testName
Hello "testName"
$ exit
bash$

Ноэто не работает в трубе, я думаю, я знаю, почему это так, но я не могу найти решение.Пример выполнения ниже.

bash$ echo -e "testName\npwd" | ./a.out
Please enter your name: warning: this program uses gets() which is unsafe.
Hello "testName"
bash$

Я полагаю, это как-то связано с тем, что gets очищает stdin таким образом, что /bin/sh получает EOF и быстро завершает работу без сообщения об ошибке.

Но как мне обойти это (не изменяя программу, если это возможно, и не удаляя gets, если нет), чтобы я получал приглашение, даже если вводил данные через канал?

PS Я запускаю это на машине с FreeBSD (4.8) DS

Ответы [ 3 ]

10 голосов
/ 14 декабря 2011

Вы можете запустить вашу программу без каких-либо модификаций, таких как:

(echo -e 'testName\n'; cat ) | ./a.out

Таким образом, вы гарантируете, что стандартный ввод вашей программы не заканчивается после того, что echo выводит.Вместо этого cat продолжает вводить данные для вашей программы.Источником этого последующего ввода является ваш терминал, поскольку именно здесь cat читает из.

Вот пример сеанса:

bash-3.2$ cc stdin_shell.c 
bash-3.2$ (echo -e 'testName\n'; cat ) | ./a.out 
Please enter your name: warning: this program uses gets(), which is unsafe.
Hello "testName"
pwd
/home/user/stackoverflow/stdin_shell_question
ls -l
total 32
-rwxr-xr-x  1 user  group  9024 Dec 14 18:53 a.out
-rw-r--r--  1 user  group   216 Dec 14 18:52 stdin_shell.c
ps -p $$
  PID TTY           TIME CMD
93759 ttys000    0:00.01 (sh)
exit

bash-3.2$

Обратите внимание, что поскольку стандартный вход оболочки не подключен ктерминал, sh считает, что он не выполняется в интерактивном режиме и, следовательно, не отображает приглашение.Вы можете печатать свои команды как обычно.

3 голосов
/ 14 декабря 2011

Использование execve("/bin/sh", 0, 0); - жестокое и необычное наказание для снаряда. Он вообще не дает никаких аргументов или среды - даже своего собственного имени программы и даже таких обязательных переменных среды, как PATH или HOME.

1 голос
/ 14 декабря 2011

Не уверен на 100% в этом (точная используемая оболочка и ОС могут выдавать эти ответы немного; я полагаю, что FreeBSD использует GNU bash по умолчанию как /bin/sh?), Но

  • sh может обнаруживать, что его вход не является tty.

или

  • Ваша версия sh может перейти в неинтерактивный режим, напримерэто также, если вызвано как sh, ожидая, что login добавит - к argv[0] для него.Настройка execve ("/bin/sh", { "-sh", NULL}, NULL) может убедить его в том, что он запускается как оболочка входа в систему.
...