理解execve的要求并设置环境变量

18
我们在解释我们的老师的话时遇到了很多麻烦。我们请求澄清,然后从他那里得到了以下回复:
1. 对于execve,使用您设置的环境并创建一个内置命令来生成/bin/bash的子shell,这样您就可以使用env查看导出的变量。 (他在谈论在此处创建自己的环境变量。)
2. 是的,请创建您自己的环境变量。您可以在shell启动时复制environ,并添加仅导出的变量。
这与我在Stack Overflow上发布的以下帖子有关(阅读此其他帖子将帮助您了解我正在尝试做什么): using a new path with execve to run ls command 我们只是非常困惑。我再次解释一下我们现在要做的事情。与Linux shell类似,我们需要编写自己的程序,以便可以设置环境变量,例如PATH和USER以及用户想要定义的任何其他变量。
您调用它的示例将是(在其提示符下的程序中):
mysetenv dog spike

这将创建一个看起来像“dog=spike”的环境变量。

更重要的是,我们需要能够设置自己的PATH变量并将其发送到exec命令。这很令人困惑,因为根据我们所有的问题,我们不理解应该做什么。

3个回答

49

其实很简单。您已经知道您的参数是char *列表,并以空指针结尾。同样,环境只是一个由char *组成的列表,以空指针结尾。通常,列表中的值采用VARNAME = var-value格式,但如果您愿意,还可以传递其他格式。

因此,以简单的情况为例:

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

int main(void)
{
    char *argv[] = { "/bin/sh", "-c", "env", 0 };
    char *envp[] =
    {
        "HOME=/",
        "PATH=/bin:/usr/bin",
        "TZ=UTC0",
        "USER=beelzebub",
        "LOGNAME=tarzan",
        0
    };
    execve(argv[0], &argv[0], envp);
    fprintf(stderr, "Oops!\n");
    return -1;
}

在这个例子中,程序将使用参数-cenv运行/bin/sh,这意味着shell将运行其当前PATH上找到的env程序。这里设置的环境以正统格式包含5个值。如果你将env改为date(或env; date),你会看到TZ设置的效果。当我在我的MacOS X机器上运行它时,输出是:

USER=beelzebub
PATH=/bin:/usr/bin
PWD=/Users/jleffler/tmp/soq
TZ=UTC0
SHLVL=1
HOME=/
LOGNAME=tarzan
_=/usr/bin/env

使用execve()调用时,shell会添加环境变量SHLVL_PWD到我明确设置的那些环境变量中。

你还可以做更炫酷的事情,比如从真实环境中复制一些其他环境变量,在它们不与你明确设置的变量冲突的情况下。你还可以玩弄一些游戏,比如在环境变量中有两个值的单个变量 - 哪一个生效?你还可以玩弄包含空格的变量名(shell并不喜欢这个),或者根本不匹配“varname=value”符号格式的条目(没有等号)。


你真的为我澄清了一切。我已经提交了所有东西,但还是谢谢!现在我明白了。 - james

9

我可能有点晚了,但如果你想保留旧的环境变量并创建新的,请使用setenv,然后将environ传递给execve()

    setenv("dog", "spike", 1);
    extern char** environ;
    execve(argv[0], argv, environ);

environ是在unistd.h中声明的一个变量,它在当前运行的进程中跟踪环境变量。

setenv()putenv()修改environ,因此当您通过execve()传递它时,环境变量将如您所期望的那样。


你不能在使用setenv扩展环境变量后,直接调用execv(argv [0],argv);吗? - Erich Kitzmueller
据我所知,环境变量本身在execve执行后不会被保留,如果你调用execve而没有传递环境变量,它将默认使用shell的环境变量。不过我可能是错的,建议你自己试一下。 - fpf3
据我理解,如果您调用 execve 函数,则必须提供一个环境变量(Linux 允许使用 NULL,这与包含单个 NULL 指针的列表具有相同的含义;但这是不可移植的)。但是,您可以调用 execv 函数(没有 e),它也会传递 environ,包括您通过调用 setenv 所做的更改。 - Erich Kitzmueller

2
Jonathan Leffler的代码很好用,但如果想要修改PWD(工作目录)变量就不行了。
为了改变工作目录,我在execve(..)之前加了一个chdir(..)来调用:
chdir("/foo/bar"); 
execve(argv[0], &argv[0], envp);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接