将 execvp 与 dup2 一起使用会引发 EFAULT 错误
Using execvp with dup2 raises EFAULT error
我正在构建一个小的 linux shell 并正在尝试实现 >
运算符以将命令的输出重定向到文件。
我遇到的问题是,当我尝试 运行 类似 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[] = {"[=10=]"};
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);
}
}
有人知道我做错了什么吗?
非常感谢
execvp
函数要求参数数组以空指针结束,而不是空字符串。
你还应该记住参数数组包括 argv[0]
.
所以数组应该是这样的
char* args[] = { "ls", NULL };
Does anyone as an idea on what I'm doing wrong here?
主要问题可能是您对 execvp()
的论点不正确:
char* args[] = {"[=10=]"};
execvp("ls", args);
有两点肯定是错误的:
参数数组需要以空指针结束。 "[=14=]"
是 不是 空指针;相反,它是一个包含两个空 字符 的数组,它会衰减为一个有效的非空指针。
即使 "[=14=]"
是一个空指针,你也会少一个参数。参数向量的第一个元素,在索引 0 处,应该是指向表示程序名称的字符串的指针。
换句话说:
char* args[] = { "ls", NULL };
execvp("ls", args);
此外,您正在执行的重定向与 POSIX shell 对 >
重定向运算符的处理不一致。在这种形式下,该运算符仅重定向标准输出,而不重定向标准错误。此外,它应该以只写方式打开指定的文件,而不是 read/write,因为写入它是程序需要做的全部。打开它 read/write 可能会导致它无法重定向到用户具有写入权限但没有读取权限的现有文件。
此外,您为创建新文件的事件指定的文件模式也会产生与 POSIX shell 不一致的行为。您应该为用户、组和其他指定 read/write 权限,并根据有效的 umask 对其进行修改:
int fd = open("test.txt", O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
我正在构建一个小的 linux shell 并正在尝试实现 >
运算符以将命令的输出重定向到文件。
我遇到的问题是,当我尝试 运行 类似 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[] = {"[=10=]"};
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);
}
}
有人知道我做错了什么吗?
非常感谢
execvp
函数要求参数数组以空指针结束,而不是空字符串。
你还应该记住参数数组包括 argv[0]
.
所以数组应该是这样的
char* args[] = { "ls", NULL };
Does anyone as an idea on what I'm doing wrong here?
主要问题可能是您对 execvp()
的论点不正确:
char* args[] = {"[=10=]"}; execvp("ls", args);
有两点肯定是错误的:
参数数组需要以空指针结束。
"[=14=]"
是 不是 空指针;相反,它是一个包含两个空 字符 的数组,它会衰减为一个有效的非空指针。即使
"[=14=]"
是一个空指针,你也会少一个参数。参数向量的第一个元素,在索引 0 处,应该是指向表示程序名称的字符串的指针。
换句话说:
char* args[] = { "ls", NULL };
execvp("ls", args);
此外,您正在执行的重定向与 POSIX shell 对 >
重定向运算符的处理不一致。在这种形式下,该运算符仅重定向标准输出,而不重定向标准错误。此外,它应该以只写方式打开指定的文件,而不是 read/write,因为写入它是程序需要做的全部。打开它 read/write 可能会导致它无法重定向到用户具有写入权限但没有读取权限的现有文件。
此外,您为创建新文件的事件指定的文件模式也会产生与 POSIX shell 不一致的行为。您应该为用户、组和其他指定 read/write 权限,并根据有效的 umask 对其进行修改:
int fd = open("test.txt", O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);