5

我必须填写以下参数:

int execve(const char *filename, char *const argv[], char *const envp[]);

如果我执行这个程序:

#include <unistd.h>
int main() {
        char *args[2];
        args[0] = "/bin/sh";
        args[1] = NULL;
        execve(args[0], args, NULL);
}

外壳按预期正确生成。

我的问题是,如果我像这样将 NULL 作为第二个参数传递,shell 也会正确生成:

#include <unistd.h>

int main() {
        char *args[2];
        args[0] = "/bin/sh";
        args[1] = NULL;
        execve(args[0], NULL, NULL);
}

那么使用 args 向量(带有“/bin/sh”+ NULL)作为第二个参数而不是 NULL 的目的是什么?

4

2 回答 2

4

在这一行中:execve(args[0], NULL, NULL);您只是使用args数组的第一个元素。您也可以使用类似char* command="/bin/sh". 你必须传递一些东西,因为这execve()就是定义的方式。在您的情况下,您通过NULL了,因为您不需要通过任何东西。

第二个参数的要点是将参数execve()传递给您正在生成的命令。假设您只是想执行 shell 而不是 shell ls,然后您可以传递 fe 这些参数:

#include <unistd.h>
int main() {
        char *args[2];
        args[0] = "/bin/ls";
        args[1] = "-lh";
        execve(args[0], args, NULL);
}

另外,引用man execve

argv 是传递给新程序的参数字符串数组。 按照惯例,这些字符串中的第一个应该包含与正在执行的文件关联的文件名。envp 是一个字符串数组,通常采用 key=value 的形式,作为环境传递给新程序。

于 2015-05-10T09:48:06.100 回答
4

如果您将空指针作为 的第二个或第三个参数传递,execve则根据 POSIX,您的程序是不正确的;这两个参数都必须是非空的。(这在的规范中execve并没有明确说明,但它在那里。)我目前正在处理传递空指针的操作系统上键入这个,

execve("executable", 0, 0);

相当于传递空数组,例如

execve("executable", (char *[]){0}, (char *[]){0});

但是得知其他操作系统会触发分段错误或返回 -1 并errno设置为EFAULTor ,我并不感到惊讶EINVAL

允许为这些参数传递空数组,但如果第二个参数是空数组,则新执行的程序将在argc/中接收零个参数,argv如果第三个参数是空数组,则 / 将在 / 中接收零个环境envp变量environ。在这些情况下,许多程序会发生故障。例如,看到类似的东西是很常见的

int main(int argc, char **argv)
{
   if (argc != 4) {
     fprintf(stderr, "usage: %s one two three\n", argv[0]);
     return 2;
   }
   // ...
}

程序隐含地假设它argv[0]总是非空的。

因此,您应该始终为两个参数提供非空数组。通常的约定是,如果您没有其他事情可做,则使用

execve(program, (char *[]){program, 0}, environ);

它提供程序自己的名称作为argv[0]没有其他参数,以及您从自己的父级获得的同一组环境变量。

于 2017-09-22T16:49:10.797 回答