uboot环境变量setenv学习

setenv是操作uboot中环境变量的一个命令

命令操作的简单回顾:

新建一个环境变量
命令行:set newenv 1
结果: newenv=1

删掉一个环境变量
命令行:set newenv
结果:这个命令就没了,printenv也不会出现。

从代码开始分析:
路径跟printenv一样
在uboot/common/cmd_nve.c
在之前的一篇忘记了,这些命令的执行都是通过U_BOOT_CMD去执行这些命令。
在setenv对应的U_BOOT_CMD中是通过调用do_setenv函数来执行命令

do_setenv:

int do_setenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	if (argc < 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	return _do_setenv (flag, argc, argv);
}

分析可知,setenv的传参个数要>=2个,小于的话会输出Usage:。。。。。
另外,do_setenv是调用的_do_setenv函数。

题外话:
函数之间的层次关系
如果函数名没有下划线_,则是自己写的,可以改动
如果函数名前面有一条_,则代表是系统调用的
如果有两条下划线__,则代表是系统内部调用的
再深一层,三条下划线___ ,层次进一步深入了,不要碰了。

_do_setenv
关于这个函数,分析的方法跟上一篇do_printenv是相类似的
通过分析,简要的可以抽出三部分来看的

第一部分,找到你要改的变量
第二部分:删掉这个变量,其实就是把这个变量的后面的往上挪移,去覆盖掉你要删或者修改单变量
第三部分:增加新的变量,或者说把你改的变量重新加在后面。

前面两个部分我都有很认真的分析过,第三部分直接从源码拷贝过来了,看了一下,大概的思路还是差不多的。
下面是整体的测试代码

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

/*DEBUG宏*/
#define __DEBUG__  
//#undef __DEBUG__
#ifdef __DEBUG__  
#define DEBUG(format,...) printf("File: "__FILE__", Line: %05d: "format"", __LINE__, ##__VA_ARGS__)  
#else  
#define DEBUG(format,...)  
#endif

#define ENV_SIZE 30

static char env_get_char_init (int index);
char env_get_char (int index);
int envmatch (char *s1, int i2);

char default_environment[30] = {"a=2\0bc=3\0wtf=45\0"};
int main(int argc,char *argv[])


//*******************************//
//解引用后指向的是\0会怎样
//*******************************//	
	
	int i = 0;
	int k = -1;
	char *env;
	char *env_data;
	char default_environment[] = {"a=2\0bc=3\0bd=45\0"};
	env_data = &default_environment[0];
	env = env_data;
	for(i=0; *env; env++)
	{
		k = 1;
		printf("i=%d\n",++i);
	}
	if(k<0)
	{
		printf("jump out of loop\n");
	}
	
	
//*******************************//
//结论:会认为是空,然后退出循环,像这里的话a = \0 \0只会循环到a = ,后面一遇到\0,表达式2不成立,转而执行表达式3了。
//*******************************//	

#endif


#if 1
//*******************************//
//测试setenv			
//编译出来之后用法:./a.out 变量名字 更改值
//char default_environment[] = {"a=2\0bc=3\0wtf=45\0"};
//需要变量从a bc wtf里面选 ,新增变量名字也可以
//*******************************//	
	
// 初始化用到的变量
	int i = 0;
	int k = -1;
	int len;
	char *name = argv[1];
	char *env, *nxt = NULL;
	char *env_data;
	//char default_environment[] = {"a=2\0bc=3\0wtf=45\0"};
	
//第一部分,找到你要改的变量
	env_data = &default_environment[0];
	env = env_data;
	int oldval = -1;
	for (env=env_data; *env; env=nxt+1) 
	{
		for (nxt=env; *nxt; ++nxt)
			;
		if ((oldval = envmatch((char *)name, env-env_data)) >= 0)
			break;
	}
	
	DEBUG("oldval = %d\n",oldval);
	DEBUG("*env = %c\n",*env);
	DEBUG("*nxt = %c\n",*nxt);
	DEBUG("*++nxt = %c\n",*++nxt);
	nxt = nxt-1;

//第二部分:删掉这个变量,其实就是把这个变量的后面的往上挪移,去覆盖掉你要删或者修改单变量
if (*++nxt == '\0')  
{
	if (env > env_data) 
	{
		env--;
		DEBUG(" aaaa *env = %c\n",*env);
	}
	else 
	{
		*env = '\0';
		DEBUG(" bbbb *env = %c\n",*env);
	}	
}

else
{
	for (;;) 
	{	
		DEBUG("before \n");
		DEBUG("*env = %c\n",*env);
		DEBUG("*nxt = %c\n",*nxt);
		*env = *nxt++;
		DEBUG("after \n");
		DEBUG("*env = %c\n",*env);
		DEBUG("*nxt = %c\n",*nxt);
		if ((*env == '\0') && (*nxt == '\0'))
		{
			break;
		}
		++env;
	}
}
//第三部分:增加新的变量,或者说把你改的变量重新加在后面。
/* Append new definition at the end*/
for (env=env_data; *env || *(env+1); ++env)
		;
	if (env > env_data)
		++env;
	/*
	 * Overflow when:
	 * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data)
	 */
	len = strlen(name) + 2;
	/* add '=' for first arg, ' ' for all others */
	for (i=2; i<argc; ++i) {
		len += strlen(argv[i]) + 1;
	}
	if (len > (&env_data[ENV_SIZE]-env)) {
		printf ("## Error: environment overflow, \"%s\" deleted\n", name);
		return 1;
	}
	while ((*env = *name++) != '\0')
		env++;
	for (i=2; i<argc; ++i) {
		char *val = argv[i];

		*env = (i==2) ? '=' : ' ';
		while ((*++env = *val++) != '\0')
			;
	}

	/* end is marked with double '\0' */
	*++env = '\0';

//测试代码,看看修改后的环境变量数组是怎样的
	int num = 0;
	for(num=0; num<sizeof(default_environment); num++)
	{
		DEBUG("default_environment[%d] = %c\n",num,default_environment[num]);
	}

//*******************************//
//结论:打印了这么多出来,其实可以发现,删掉了是真没了,是用后面的往前挪来覆盖要删掉的。
//然后新的环境变量是会被挪移到最后,在最后面添加的。
#endif 


	return 0;
}





int envmatch (char *s1, int i2)
{
	/* printf("before while: i2 = %d\n",i2);
	printf("before while: s1 = %c\n",*s1);
	printf("before while: env_get_char(i2++) = %c\n",env_get_char(i2++));
	i2=i2-1; */
	while (*s1 == env_get_char(i2++))
	{
		/* printf("after while : *s1 = %c\n",*s1);
		printf("after while : i2 = %d\n",i2);
		
		printf("after while : *s1++ = %c\n",*s1++);
		s1=s1-1; */
		if (*s1++ == '=') 
		{
			
		//	printf("after while if : i2 = %d\n",i2);
			return(i2);
		}
		//printf("after if: *s1 = %c\n",*s1);
		
		
		 
	}
	 if (*s1 == '\0' && env_get_char(i2-1) == '=')
		return(i2);
	 
	return(-1);
}

char env_get_char (int index)
{
	char c;

	c = env_get_char_init(index);

	return (c);
}

static char env_get_char_init (int index)
{
	char c;
	//char default_environment[] = {"a=2\0bc=3\0wtf=45\0"};
	c = default_environment[index];

	return (c);
}

这里我把环境变量数组的大小设置为30了,所以只有30个位置,但是够测试用。
下面是测试结果。
char default_environment[30] = {“a=2\0bc=3\0wtf=45\0”};
这是我设置的默认环境变量,数组大小30,里面默认存的值是a=2\0bc=3\0wtf=45\0,然后我测试的时候把a改成了33,结果a的环境变量被改了,后面的往前挪移,覆盖了原来a的环境变量,然后修改好的a的环境变量在最后面出现。这个测试结果是跟在uboot里面测试的时候是一样的。
在这里插入图片描述

总结一下
1.重点是要理解环境变量的存储方式
例如这样:char default_environment[30] = {“a=2\0bc=3\0wtf=45\0”};
2.如果指针指向的位置存的是\0的话,那么解引用之后就是为空的(假的),所以if或者for循环的表达式2都不会成立
3.能读懂代码最好,如果代码比较复杂的话,可以像这样做一些测试代码,在linux下的话可以printf打印调试信息来检查校验,帮助理解代码。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值