【问题标题】:What is the correct step to execute execve()?执行 execve() 的正确步骤是什么?
【发布时间】:2019-07-28 21:28:10
【问题描述】:

我们的作业需要使用 pipe()、fork()、execve() 和 dup() 来实现一个简单的使用管道执行终端命令。所以我阅读了 dup 和 pipe 如何操作文件描述符,并生成了下面的代码。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int pfds[2];
    pipe(pfds);

    if (!fork()) {
        close(1);       /* close normal stdout */
        dup(pfds[1]);   /* make stdout same as pfds[1] */
        close(pfds[0]); /* we don't need this */
        char *k = {"echo", "one", "two", "three", NULL};
        execve("/bin/echo", k, NULL);
    } else {
        close(0);       /* close normal stdin */
        dup(pfds[0]);   /* make stdin same as pfds[0] */
        close(pfds[1]); /* we don't need this */
        char *k = {"wc", "-w", NULL};
        execve("/usr/bin/wc", k, NULL);
    }

    return 0;
}

运行代码似乎没有任何结果,我不确定我还需要什么才能使其工作。

我期待输出 3,正如您通过输入看到的那样

echo one two three | wc -w 在终端中。顺便说一下,我使用的是 MacOS。

【问题讨论】:

  • 1) 你甚至不应该尝试关闭 1 和 0。2) 你使用 dup 函数和管道输出是不对的。最好阅读手册页以获得完整的解释,但想法是创建一个“管道”,您的程序将与 pipe() 一起使用。 fork 的父级将在此管道的一侧写入,子级将在另一侧读取。然后,您需要复制管道入口/出口的 1 或 0(取决于)。最后不要忘记关闭您不使用的管道部分(仅在父/子分隔的代码中,不要在主要部分中关闭两者,否则什么都不起作用B-))
  • 请注意,您将执行的程序传递给一个空环境。那不是你应该做的。要么传入自定义环境,要么使用进程自己的环境(在任何函数之外使用extern char **environ;——这未在任何 POSIX 标头中声明——然后使用environ 作为execve() 的第三个参数,或者使用execv()而不是execve(),因为你不是在修补环境。
  • @Angevil dup 的使用似乎几乎正确但丑陋 - 应该使用 dup2 代替
  • @AnttiHaapala 你对这个警告是对的,如果我看一下,我本可以找出问题所在。我不确定您所说的“dup 几乎正确但丑陋”是什么意思,您能分享更多信息吗?
  • @AnttiHaapala 事实上,这段代码在这种情况下并不健壮,但除非提问者以一种奇怪的方式运行程序,否则在她/他运行它时不应该阻止它工作。跨度>

标签: c pipe system-calls execve


【解决方案1】:

问题是您将字符串数组分配给char*。两个ks 都应该声明为char* k[] = …。如果您的编译器没有对此发出警告,您需要启用更多警告。

与评论相反,您正确使用了closedup(但dup2 会更好)。

【讨论】:

  • close()dup() 的调用,如您所说,本身是正确的,使用dup2() 也会更好。然而,正如我在comment 中所指出的,另一个被复制的文件描述符也应该被关闭。如果第一个命令不是执行echo,而是读取它的标准输入,这将是显而易见的;它不会终止,因为它不会在其标准输入上获得 EOF,因为它打开了管道的写入端,即使它永远不会写入它。
  • @JonathanLeffler:这不是关闭那个描述符(dup(pfds[1]); close(pfds[0]);),问题是有一个不必要的描述符挂在周围吗?还是我误会了?
  • 否; dup(pfds[1]) 不会关闭 pfds[1]close(pfds[0]) 也不会关闭——所以当执行发生时,pfds[1](可能是文件描述符 4)在进程中仍然打开。它没有标记为O_CLOEXEC(在执行时关闭),因此exec 也不会关闭它。 (没有F_DUPFD_CLOEXECFD_CLOEXEC...)
  • @JonathanLeffler:“如果第一个命令不执行回显,而是读取其标准输入;它不会终止,因为它不会在其标准输入上获得 EOF”——它的标准输入没有改变,不是吗?
  • 嗯……你可能是正确的,我的替代方案不会产生我声称的问题——但即使我没有诊断出有效的方案(我试图保持简单,但错过了) ,然而,在更复杂的管道中,不关闭两个管道文件描述符可能会导致问题。最好不要让不应打开的文件描述符保持打开状态。在某些情况下,它也可能存在安全风险。
猜你喜欢
  • 2021-09-30
  • 2014-10-02
  • 2019-09-10
  • 1970-01-01
  • 2012-05-02
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 2016-07-28
相关资源
最近更新 更多