execve(“/bin/sh”, 0, 0);在管道中

发布于 2024-12-21 05:54:07 字数 915 浏览 1 评论 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);
}

当我在没有任何管道的情况下运行时,它会正常工作并返回 sh 提示:

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/bin/sh 接收 EOF 并立即退出的方式清空 stdin 的事实有关没有错误消息。

但是我如何解决这个问题(如果可能的话,不修改程序,如果不是的话,不删除 gets),以便即使我通过管道提供输入也能得到提示?

PS 我在 FreeBSD (4.8) 机器 DS 上运行它

I have the following example program:

#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 and when I run without any pipe it works as it should and returns a sh promt:

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

But this does not work in a pipe, i think I know why that is, but I cannot figure out a solution. Example run bellow.

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

I figure this has something to do with the fact that gets empties stdin in such a way that /bin/sh receives a EOF and promtly quits without an error message.

But how do I get around this (without modifying the program, if possible, and not removing gets, if not) so that I get a promt even though I supply input through a pipe?

P.S. I am running this on a FreeBSD (4.8) machine D.S.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

酒与心事 2024-12-28 05:54:07

您可以在不进行任何修改的情况下运行您的程序,如下所示:

(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$

请注意,由于 shell 的标准输入未连接到终端,因此 sh 认为它不是交互式执行的,因此不会显示提示符。不过,您可以正常键入命令。

You can run your program without any modifications like this:

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

This way you ensure that your program's standard input doesn't end after what echo outputs. Instead, cat continues to supply input to your program. The source of that subsequent input is your terminal since this is where cat reads from.

Here's an example session:

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$

Note that because shell's standard input is not connected to a terminal, sh thinks it is not executed interactively and hence does not display the prompt. You can type your commands normally, though.

紧拥背影 2024-12-28 05:54:07

使用 execve("/bin/sh", 0, 0); 对 shell 来说是残酷且不寻常的惩罚。它根本没有给它任何参数或环境——甚至没有它自己的程序名称,甚至没有诸如 PATH 或 HOME 之类的强制环境变量。

Using execve("/bin/sh", 0, 0); is cruel and unusual punishment for the shell. It gives it no arguments or environment at all - not even its own program name, nor even such mandatory environment variables as PATH or HOME.

知你几分 2024-12-28 05:54:07

不能 100% 确定这一点(所使用的精确 shell 和操作系统可能会抛出这些答案;我相信 FreeBSD 默认使用 GNU bash 作为 /bin/sh ?),但

  • sh 可能会检测到其输入不是 tty。

或者

  • 您的 sh 版本可能会进入非交互模式,如果调用为 sh,则期望 login 会在前面添加 -argv[0] 上。设置 execve ("/bin/sh", { "-sh", NULL}, NULL) 可能会使其相信它正在作为登录 shell 运行。

Not 100% sure of this (the precise shell being used and the OS might throw these answers a bit; I believe that FreeBSD uses GNU bash by default as /bin/sh?), but

  • sh may be detecting that its input is not a tty.

or

  • Your version of sh might go into non-interactive mode like that also if called as sh, expecting login will prepend a - onto argv[0] for it. Setting up execve ("/bin/sh", { "-sh", NULL}, NULL) might convince it that it's being run as a login shell.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文