到底什么是环境变量, 系统管理上常常会关联上环境变量。平时用就会用。但是没有对它有一个明确的定义。这有碍工作中对它的深刻使用。
带来的疑問:
1. 环境变量中的"变量"是编程语言中的"变量"?
2. 环境变量中的“变量”是存在于kernel中的?
jessinio@jessinio-laptop:/usr/src/linux$ grep -r "putenv" *
从搜索結果可以看出, enviroment不是kernel的东西。
如果环境变量就是普通的变量, 为什么需要特殊的函数去操作, 如C语言的getenv和putenv
要想知道这一切, 应该从libc6代码开始, 下载代码后, 发现:
char *
getenv (name)
const char *name;
{
size_t len = strlen (name);
char **ep;
uint16_t name_start;
if (__environ == NULL || name[0] == '\0')
return NULL;
if (name[1] == '\0')
...(下面被截掉)...
可以看到一个__environ的变量. 难道是global变量? 自己写下面的代码测试一下这个变量是否真会存在:
#include <stdlib.h>
#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
char *env_key = "PATH";
char *env_value = getenv(env_key);
printf("get value by getenv function: \n\t%s\n", env_value);
printf("get value by __environ variable\n");
int env_len = sizeof(__environ);
int i;
for (i =0; i <= env_len; i++)
{
printf("\t%s\n", __environ[i]);
}
return 0;
}
OK, 这个变量真的会存在. "环境变量其实就是普通变量"这句话已经有一半可能是正确的了. 下面再看看__environ哪来的
如果没有#include <unistd.h> , gcc出错: get_env.c:15: error: ‘__environ’ undeclared (first use in this function)
OK, 表示这个__environ来源于这个header文件. 找这个header文件:
jessinio@jessinio-laptop:/tmp/eglibc-2.10.1/stdlib$ find /usr/include -name unistd.h
/usr/include/linux/unistd.h
/usr/include/bits/unistd.h
/usr/include/asm-generic/unistd.h
/usr/include/sys/unistd.h
/usr/include/unistd.h
/usr/include/asm/unistd.h
看看/usr/include/unistd.h的内容:
/* NULL-terminated array of "NAME=VALUE" environment variables. */
extern char **__environ;
#ifdef __USE_GNU
extern char **environ;
#endif
__environ为char型二元数组. 说穿了就是一个global变量。 下面做一个测试, 直接修改__environ变量的值, 测试能否传递到子进程中。代码如下:
#include <stdlib.h>
#include <sys/types.h>
#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
int startswith(char *str1, char *str2)
{
//like python string instance : 'SHELL=/bin/bash'.startswith("SHELL") is True
size_t copy_len;
copy_len = strlen(str2);
// temporary variable
// tmp_str[-1] maybe '\0' char
char tmp_str[ copy_len ];
strncpy(tmp_str, str1, copy_len);
// string arrary need '\0' char at the end
tmp_str[copy_len] = '\0';
int retval;
retval = strcmp(str2, tmp_str);
return retval;
}
int main(int argc, char* argv[])
{
char *env_key = "SHELL";
char *env_value = getenv(env_key);
printf("get value by getenv function: \n\t%s\n", env_value);
printf("set new value by modify __environ variable\n");
int env_len = sizeof(__environ);
int i;
for (i =0; i <= env_len; i++)
{
int retval;
retval = startswith(__environ[i], env_key);
if ( retval == 0)
{
// OK! modify the value
__environ[i] = "SHELL=/usr/bin/python";
//printf("\t%s\n", __environ[i]);
}
}
// create child process
pid_t pid;
pid = fork();
if (pid == 0)
{
//printf("I am child process\n");
execl("/usr/bin/python", "/usr/bin/python", "/tmp/get_env.py", (char *)0);
}
if (pid != 0)
{
//printf("I am parent process\n");
sleep(2);
waitpid(pid);
}
return 0;
}
get_env.py的代码:
import os
print os.environ['SHELL']
输出結果为:
jessinio@jessinio-laptop:/tmp$ gcc get_env.c
jessinio@jessinio-laptop:/tmp$ ./a.out
get value by getenv function:
/bin/bash
set new value by modify __environ variable
/usr/bin/python
可见, 不通过setenv这种的stdlib函数照样可以修改环境变量并传递到子进程。 即: 环境变量其实就是普通变量, 程序的全局变量
现在变量可以存在了, 还有一个问题: fork函数到底到了什么, 哪些数据是保留给子进程了. fork函数无疑是kernel的东西, 位于kernel/fork.c
下部就下次写。
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.