C execve() 参数 [生成一个 shell 示例]

C execve() parameters [spawn a shell example]

我必须填写以下参数:

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);
}

shell 按预期正确生成。

我的问题是,如果我将 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 的目的是什么?

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

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

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

此外,引用 man execve:

argv is an array of argument strings passed to the new program. By convention, the first of these strings should contain the filename associated with the file being executed. envp is an array of strings, conventionally of the form key=value, which are passed as environment to the new program.

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

execve("executable", 0, 0);

相当于传递空数组,例如

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

但当我得知其他操作系统会触发分段错误或 return -1 且 errno 设置为 EFAULTEINVAL 时,我不会感到惊讶。

允许为这些参数传递空数组,但如果第二个参数是空数组,新执行的程序将在 argc/argv 中接收零参数,and/or 零如果第三个参数是空数组,则 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] 并且没有进一步的参数,以及您从自己的父级获得的相同环境变量集。