将execvp与dup2一起使用会引发EFAULT错误

时间:2019-02-01 14:04:16

标签: c linux execvp dup2

我建立一个小的Linux壳和想实现的>操作者的命令的输出重定向到文件中。

我遇到的问题是,当我尝试运行类似ls > test.txt之类的东西时,出现Bad Address(EFAULT)错误。

但是,如果我尝试不使用重定向,一切都会按预期进行。

我已将代码修整到最低限度,以仅测试ls,但仍然出现相同的错误,这是代码。

int saved_stdout;
__pid_t id = fork();

if (id == 0) {
    saved_stdout = dup(1);

    int fd = open("test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);

    close(fd);

    char* args[] = {"\0"};

    execvp("ls", args);

    fprintf(stderr, "Value of errno: %d\n", errno);
    perror("Error printed by perror");

} else {
    int status;
    waitpid(id, &status, 0);

    if (saved_stdout) {
        dup2(saved_stdout, 1);
        close(saved_stdout);
    }
}

有人认为我在这里做错了吗?

非常感谢

2 个答案:

答案 0 :(得分:3)

execvp函数期望参数数组以空指针而不是空字符串终止。

您还应该记住的是,参数阵列包括argv[0]

因此,阵列应该像

char* args[] = { "ls", NULL };

答案 1 :(得分:1)

  

有人认为我在这里做错了吗?

主要问题可能是您对execvp()的论点不正确:

    char* args[] = {"\0"};

    execvp("ls", args);

肯定有两件事是错误的:

  1. 参数数组需要以空指针终止。 "\0" 不是空指针;而是一个包含两个个字符的数组,它衰减为有效的指针,因此为非null。

  2. 即使"\0"是空指针,您也将成为一个短参数。参数向量的第一个元素在索引0处应该是指向表示程序名称的字符串的指针。

换句话说:

 char* args[] = { "ls", NULL };

 execvp("ls", args);

此外,您正在执行的重定向与POSIX shell对>重定向操作符的处理不一致。以这种形式,该操作员仅重定向标准输出,而不重定向标准错误。此外,它应该以只读方式打开指定的文件,而不是读/写,因为对其进行写入是程序需要做的所有事情。对其进行读写操作可能导致它无法重定向到用户具有写权限但没有读权限的现有文件。

此外,为创建新文件而指定的文件模式也会产生与POSIX shell不一致的行为。您应该为用户,组和其他用户指定读/写权限,并根据有效的umask对其进行修改:

int fd = open("test.txt", O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);