Execve ( "/bin/sh", 0, 0); в трубе
У меня есть следующая примерная программа:
#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
, если нет), так что я получаю promt, даже если я предоставляю вход через канал?
P.S. Я запускаю это на машине FreeBSD (4.8) D.S.
Ответы
Ответ 1
Вы можете запускать свою программу без каких-либо изменений:
(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
считает, что он не выполняется интерактивно и, следовательно, не отображает подсказку. Однако вы можете вводить свои команды.
Ответ 2
Использование execve("/bin/sh", 0, 0);
- жестокое и необычное наказание для оболочки. Это не дает никаких аргументов или среды вообще - даже не его собственное имя программы, и даже такие обязательные переменные окружения, как PATH или HOME.
Ответ 3
Не на 100% уверен в этом (точная оболочка используется, и ОС может немного отбросить эти ответы, я полагаю, что FreeBSD по умолчанию использует GNU bash
как /bin/sh
?), но
-
sh
может обнаруживать, что его вход не является tty.
или
- Ваша версия
sh
может перейти в неинтерактивный режим, например, если вызывается как sh
, ожидая, что login
добавит к ней -
на argv[0]
. Настройка execve ("/bin/sh", { "-sh", NULL}, NULL)
может убедить ее, что она запускается как оболочка входа.