【问题标题】:How to set the environment variable of child same as parent to use execve in C?如何设置子环境变量与父环境变量相同以在C中使用execve?
【发布时间】:2016-07-14 03:44:15
【问题描述】:

我试图设置类似于父进程的子进程的环境,我需要用字符串填充名为 envp 的数组,如下所示:

char *envp = malloc(sizeof(args) / sizeof(char *));
strcpy(envp[0], strcat("HOME=", getenv("HOME")));
envp[1] = strcat("PATH=", getenv("PATH"));
envp[2] = strcat("TZ=", getenv("TZ"));
envp[3] = strcat("USER=", getenv("USER"));
envp[4] = strcat("LOGNAME=", getenv("LOGNAME"));
envp[5] = 0;

内部 if(fork() ==0)

setenv("parent", cwd, 1);
if((execve(args[0], &args[0], envp)) < 0 ){
            perror(*args);
            exit(EXIT_FAILURE);
}

我这样做是因为我不知道这些环境变量的值,所以我想复制父变量以便在将替换子进程的 execve() 中使用它们! 我使用 execve() 而不是 execvp() 因为我想在执行命令之前处理搜索 cwd 并搜索未找到 cwd 的 shell 路径名的目录。

所以我的问题是:如何以正确的方式设置数组的值? 另外,我是否误解了任何概念?

我在这里看了很多帖子,但很明显我迷路了! 提前致谢,

【问题讨论】:

  • char *envp 是错误的。您需要一个 array 字符指针。 execve() 还需要一个 char* 指针数组作为其第三个参数。 envp[1] = strcat( 完全错误。 envp[1] 是一个字符。一个字符,而不是指针。 strcat() 的工作方式与您认为的不同。 (并且第一个参数必须指向一个可写的字符数组,而不是字符串字面量。)

标签: c shell environment-variables exec


【解决方案1】:

您没有为envp [x] 指向的字符串分配内存。相反,您尝试将 strcatstrcpy 设置为常量或未分配的字符串,这是一个禁忌(您的编译器很可能已经警告过您)

一般概念是

  1. 您需要为指向环境的指针数组分配内存 字符串(你做到了)。
  2. 您还需要为这些指针指向的每个字符串分配内存(您没有这样做)。请注意,在大多数操作系统中,内存属于进程环境的所有权,因此您不能使用局部变量,并且您可能不会free 这块内存。
  3. 您需要将从 (2) 检索到的指针保存到您在 (1) 分配的数组位置中(您这样做了)

您的代码应类似于(仅适用于“HOME”的示例,envbuff 的长度可能需要调整/检查):

char envBuff [100];

strcpy (envBuff, "HOME=");
strcat (envBuff, getenv ("HOME));
envp [0] = strdup (envBuff);

strdup实际上分配它使用的内存,strcat或像envp[0]所做的简单分配不要-strcat假设有足够的空间容纳原始并且附加部分和内存是可写的,这在你的情况下都是不正确的。

【讨论】:

  • 使用这种方式向我显示这个警告:“赋值从指针中生成整数而不进行强制转换[默认启用]”,我厌倦了关注这篇文章(虽然我认为这不是正确的方式),但仍然得到同样的警告!有什么提示可以解决这个问题吗? stackoverflow.com/questions/21858412/…
  • 这一行:envp [0] = strdup (envBuff);
  • @meramees 你的malloc 应该分配char** 的数组而不是char* 的数组。 char **envp = malloc...
【解决方案2】:
  • strcat() 是个糟糕的函数
  • 也可以选择为每个“Name=value”对使用单独的 strdup()。
  • 将所有字符串放在一块内存中会更好
  • snprintf() 永远不会超出允许的大小;相反,它会为您提供所需的尺寸
  • getenv() 可以返回 NULL,这必须处理

注意:我省略了 realloc() 返回 NULL 的检查,你应该添加这些。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define COUNTOF(a) (sizeof a / sizeof a[0])
char * names[] = {"HOME", "PATH", "TZ", "USER", "LOGNAME", NULL};

int main(void)
{
char *all=NULL;
char *array[COUNTOF(names) ];
size_t size, used, idx, envc, len;

for (idx=envc=size=used= 0; names[idx] ; idx++ ) {
        char *cp;
        cp = getenv(names[idx] );
        if (!cp) {
                fprintf(stderr, "%s not found\n", names[idx] );
                continue;
                }
        fprintf(stderr, "%s found: \"%s\"\n", names[idx], cp );
        while(1) {
                len = snprintf(all+used, size-used, "%s=%s", names[idx], cp);
                        /* enough space for the "NAME=val\0" pair */
                if (len+1 < size-used) break;
                fprintf(stderr, "Len=%zu; realloc %zu += %zu\n" , len, size, 2*len+1 );
                all = realloc(all, size += 2*len+1);
                }
        array[envc++] = all+used; used += len+1;
        }

fprintf(stderr, "Final realloc %zu -->> %zu\n" , size, used+1 );
all = realloc(all, used+1);
array[envc] = NULL;

for (idx=0; idx < envc; idx++) {
        printf("[%zu] -> %s\n", idx, array[idx] );
        }

return 0;
}

顺便说一句:如果您的操作系统/环境允许,您可以将 main() 定义为

int main(int argc, char **argv, char **envp) { ... }

,并使用父进程现有的env指针。

【讨论】:

  • 感谢您的详细回答。当我尝试一点一点地遵循这段代码,然后将数组作为第三个参数传递给 execve() 时,我得到了这个我不知道如何处理的异常! myshell_3.c:390:7:警告:从不兼容的指针类型传递“execve”的参数 3 [默认启用] if((execve(args[0], &args[0], envp))
  • 那是愚蠢的常量。 (execve() 无论如何都不应该返回)放弃它,或者更好:改变 main(...) 中的参数类型您的代码还在某处遗漏了*,envp 应该是指向指针的指针。
  • 我是初学者,我迷路了!你能指出我可以修改的行以及如何修改它们吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-29
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
  • 2014-12-17
  • 2011-03-25
  • 2016-02-04
相关资源
最近更新 更多