xref: /OK3568_Linux_fs/u-boot/env/flags.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2012
3*4882a593Smuzhiyun  * Joe Hershberger, National Instruments, joe.hershberger@ni.com
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/string.h>
9*4882a593Smuzhiyun #include <linux/ctype.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
12*4882a593Smuzhiyun #include <stdint.h>
13*4882a593Smuzhiyun #include <stdio.h>
14*4882a593Smuzhiyun #include "fw_env_private.h"
15*4882a593Smuzhiyun #include "fw_env.h"
16*4882a593Smuzhiyun #include <env_attr.h>
17*4882a593Smuzhiyun #include <env_flags.h>
18*4882a593Smuzhiyun #define env_get fw_getenv
19*4882a593Smuzhiyun #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
20*4882a593Smuzhiyun #else
21*4882a593Smuzhiyun #include <common.h>
22*4882a593Smuzhiyun #include <environment.h>
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #ifdef CONFIG_CMD_NET
26*4882a593Smuzhiyun #define ENV_FLAGS_NET_VARTYPE_REPS "im"
27*4882a593Smuzhiyun #else
28*4882a593Smuzhiyun #define ENV_FLAGS_NET_VARTYPE_REPS ""
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
32*4882a593Smuzhiyun static const char env_flags_varaccess_rep[] = "aroc";
33*4882a593Smuzhiyun static const int env_flags_varaccess_mask[] = {
34*4882a593Smuzhiyun 	0,
35*4882a593Smuzhiyun 	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
36*4882a593Smuzhiyun 		ENV_FLAGS_VARACCESS_PREVENT_CREATE |
37*4882a593Smuzhiyun 		ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
38*4882a593Smuzhiyun 	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
39*4882a593Smuzhiyun 		ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
40*4882a593Smuzhiyun 	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
41*4882a593Smuzhiyun 		ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #ifdef CONFIG_CMD_ENV_FLAGS
44*4882a593Smuzhiyun static const char * const env_flags_vartype_names[] = {
45*4882a593Smuzhiyun 	"string",
46*4882a593Smuzhiyun 	"decimal",
47*4882a593Smuzhiyun 	"hexadecimal",
48*4882a593Smuzhiyun 	"boolean",
49*4882a593Smuzhiyun #ifdef CONFIG_CMD_NET
50*4882a593Smuzhiyun 	"IP address",
51*4882a593Smuzhiyun 	"MAC address",
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun static const char * const env_flags_varaccess_names[] = {
55*4882a593Smuzhiyun 	"any",
56*4882a593Smuzhiyun 	"read-only",
57*4882a593Smuzhiyun 	"write-once",
58*4882a593Smuzhiyun 	"change-default",
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun  * Print the whole list of available type flags.
63*4882a593Smuzhiyun  */
env_flags_print_vartypes(void)64*4882a593Smuzhiyun void env_flags_print_vartypes(void)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	enum env_flags_vartype curtype = (enum env_flags_vartype)0;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	while (curtype != env_flags_vartype_end) {
69*4882a593Smuzhiyun 		printf("\t%c   -\t%s\n", env_flags_vartype_rep[curtype],
70*4882a593Smuzhiyun 			env_flags_vartype_names[curtype]);
71*4882a593Smuzhiyun 		curtype++;
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun  * Print the whole list of available access flags.
77*4882a593Smuzhiyun  */
env_flags_print_varaccess(void)78*4882a593Smuzhiyun void env_flags_print_varaccess(void)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	while (curaccess != env_flags_varaccess_end) {
83*4882a593Smuzhiyun 		printf("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess],
84*4882a593Smuzhiyun 			env_flags_varaccess_names[curaccess]);
85*4882a593Smuzhiyun 		curaccess++;
86*4882a593Smuzhiyun 	}
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /*
90*4882a593Smuzhiyun  * Return the name of the type.
91*4882a593Smuzhiyun  */
env_flags_get_vartype_name(enum env_flags_vartype type)92*4882a593Smuzhiyun const char *env_flags_get_vartype_name(enum env_flags_vartype type)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	return env_flags_vartype_names[type];
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun  * Return the name of the access.
99*4882a593Smuzhiyun  */
env_flags_get_varaccess_name(enum env_flags_varaccess access)100*4882a593Smuzhiyun const char *env_flags_get_varaccess_name(enum env_flags_varaccess access)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	return env_flags_varaccess_names[access];
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun #endif /* CONFIG_CMD_ENV_FLAGS */
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /*
107*4882a593Smuzhiyun  * Parse the flags string from a .flags attribute list into the vartype enum.
108*4882a593Smuzhiyun  */
env_flags_parse_vartype(const char * flags)109*4882a593Smuzhiyun enum env_flags_vartype env_flags_parse_vartype(const char *flags)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	char *type;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
114*4882a593Smuzhiyun 		return env_flags_vartype_string;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	type = strchr(env_flags_vartype_rep,
117*4882a593Smuzhiyun 		flags[ENV_FLAGS_VARTYPE_LOC]);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if (type != NULL)
120*4882a593Smuzhiyun 		return (enum env_flags_vartype)
121*4882a593Smuzhiyun 			(type - &env_flags_vartype_rep[0]);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	printf("## Warning: Unknown environment variable type '%c'\n",
124*4882a593Smuzhiyun 		flags[ENV_FLAGS_VARTYPE_LOC]);
125*4882a593Smuzhiyun 	return env_flags_vartype_string;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /*
129*4882a593Smuzhiyun  * Parse the flags string from a .flags attribute list into the varaccess enum.
130*4882a593Smuzhiyun  */
env_flags_parse_varaccess(const char * flags)131*4882a593Smuzhiyun enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	char *access;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
136*4882a593Smuzhiyun 		return env_flags_varaccess_any;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	access = strchr(env_flags_varaccess_rep,
139*4882a593Smuzhiyun 		flags[ENV_FLAGS_VARACCESS_LOC]);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (access != NULL)
142*4882a593Smuzhiyun 		return (enum env_flags_varaccess)
143*4882a593Smuzhiyun 			(access - &env_flags_varaccess_rep[0]);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	printf("## Warning: Unknown environment variable access method '%c'\n",
146*4882a593Smuzhiyun 		flags[ENV_FLAGS_VARACCESS_LOC]);
147*4882a593Smuzhiyun 	return env_flags_varaccess_any;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun  * Parse the binary flags from a hash table entry into the varaccess enum.
152*4882a593Smuzhiyun  */
env_flags_parse_varaccess_from_binflags(int binflags)153*4882a593Smuzhiyun enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	int i;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(env_flags_varaccess_mask); i++)
158*4882a593Smuzhiyun 		if (env_flags_varaccess_mask[i] ==
159*4882a593Smuzhiyun 		    (binflags & ENV_FLAGS_VARACCESS_BIN_MASK))
160*4882a593Smuzhiyun 			return (enum env_flags_varaccess)i;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	printf("Warning: Non-standard access flags. (0x%x)\n",
163*4882a593Smuzhiyun 		binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	return env_flags_varaccess_any;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
is_hex_prefix(const char * value)168*4882a593Smuzhiyun static inline int is_hex_prefix(const char *value)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
skip_num(int hex,const char * value,const char ** end,int max_digits)173*4882a593Smuzhiyun static void skip_num(int hex, const char *value, const char **end,
174*4882a593Smuzhiyun 	int max_digits)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	int i;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (hex && is_hex_prefix(value))
179*4882a593Smuzhiyun 		value += 2;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	for (i = max_digits; i != 0; i--) {
182*4882a593Smuzhiyun 		if (hex && !isxdigit(*value))
183*4882a593Smuzhiyun 			break;
184*4882a593Smuzhiyun 		if (!hex && !isdigit(*value))
185*4882a593Smuzhiyun 			break;
186*4882a593Smuzhiyun 		value++;
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 	if (end != NULL)
189*4882a593Smuzhiyun 		*end = value;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun #ifdef CONFIG_CMD_NET
eth_validate_ethaddr_str(const char * addr)193*4882a593Smuzhiyun int eth_validate_ethaddr_str(const char *addr)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	const char *end;
196*4882a593Smuzhiyun 	const char *cur;
197*4882a593Smuzhiyun 	int i;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	cur = addr;
200*4882a593Smuzhiyun 	for (i = 0; i < 6; i++) {
201*4882a593Smuzhiyun 		skip_num(1, cur, &end, 2);
202*4882a593Smuzhiyun 		if (cur == end)
203*4882a593Smuzhiyun 			return -1;
204*4882a593Smuzhiyun 		if (cur + 2 == end && is_hex_prefix(cur))
205*4882a593Smuzhiyun 			return -1;
206*4882a593Smuzhiyun 		if (i != 5 && *end != ':')
207*4882a593Smuzhiyun 			return -1;
208*4882a593Smuzhiyun 		if (i == 5 && *end != '\0')
209*4882a593Smuzhiyun 			return -1;
210*4882a593Smuzhiyun 		cur = end + 1;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun #endif
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun /*
218*4882a593Smuzhiyun  * Based on the declared type enum, validate that the value string complies
219*4882a593Smuzhiyun  * with that format
220*4882a593Smuzhiyun  */
_env_flags_validate_type(const char * value,enum env_flags_vartype type)221*4882a593Smuzhiyun static int _env_flags_validate_type(const char *value,
222*4882a593Smuzhiyun 	enum env_flags_vartype type)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	const char *end;
225*4882a593Smuzhiyun #ifdef CONFIG_CMD_NET
226*4882a593Smuzhiyun 	const char *cur;
227*4882a593Smuzhiyun 	int i;
228*4882a593Smuzhiyun #endif
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	switch (type) {
231*4882a593Smuzhiyun 	case env_flags_vartype_string:
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun 	case env_flags_vartype_decimal:
234*4882a593Smuzhiyun 		skip_num(0, value, &end, -1);
235*4882a593Smuzhiyun 		if (*end != '\0')
236*4882a593Smuzhiyun 			return -1;
237*4882a593Smuzhiyun 		break;
238*4882a593Smuzhiyun 	case env_flags_vartype_hex:
239*4882a593Smuzhiyun 		skip_num(1, value, &end, -1);
240*4882a593Smuzhiyun 		if (*end != '\0')
241*4882a593Smuzhiyun 			return -1;
242*4882a593Smuzhiyun 		if (value + 2 == end && is_hex_prefix(value))
243*4882a593Smuzhiyun 			return -1;
244*4882a593Smuzhiyun 		break;
245*4882a593Smuzhiyun 	case env_flags_vartype_bool:
246*4882a593Smuzhiyun 		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
247*4882a593Smuzhiyun 		    value[0] != 'Y' && value[0] != 'T' &&
248*4882a593Smuzhiyun 		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
249*4882a593Smuzhiyun 		    value[0] != 'N' && value[0] != 'F')
250*4882a593Smuzhiyun 			return -1;
251*4882a593Smuzhiyun 		if (value[1] != '\0')
252*4882a593Smuzhiyun 			return -1;
253*4882a593Smuzhiyun 		break;
254*4882a593Smuzhiyun #ifdef CONFIG_CMD_NET
255*4882a593Smuzhiyun 	case env_flags_vartype_ipaddr:
256*4882a593Smuzhiyun 		cur = value;
257*4882a593Smuzhiyun 		for (i = 0; i < 4; i++) {
258*4882a593Smuzhiyun 			skip_num(0, cur, &end, 3);
259*4882a593Smuzhiyun 			if (cur == end)
260*4882a593Smuzhiyun 				return -1;
261*4882a593Smuzhiyun 			if (i != 3 && *end != '.')
262*4882a593Smuzhiyun 				return -1;
263*4882a593Smuzhiyun 			if (i == 3 && *end != '\0')
264*4882a593Smuzhiyun 				return -1;
265*4882a593Smuzhiyun 			cur = end + 1;
266*4882a593Smuzhiyun 		}
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 	case env_flags_vartype_macaddr:
269*4882a593Smuzhiyun 		if (eth_validate_ethaddr_str(value))
270*4882a593Smuzhiyun 			return -1;
271*4882a593Smuzhiyun 		break;
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun 	case env_flags_vartype_end:
274*4882a593Smuzhiyun 		return -1;
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/* OK */
278*4882a593Smuzhiyun 	return 0;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun /*
282*4882a593Smuzhiyun  * Look for flags in a provided list and failing that the static list
283*4882a593Smuzhiyun  */
env_flags_lookup(const char * flags_list,const char * name,char * flags)284*4882a593Smuzhiyun static inline int env_flags_lookup(const char *flags_list, const char *name,
285*4882a593Smuzhiyun 	char *flags)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	int ret = 1;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	if (!flags)
290*4882a593Smuzhiyun 		/* bad parameter */
291*4882a593Smuzhiyun 		return -1;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	/* try the env first */
294*4882a593Smuzhiyun 	if (flags_list)
295*4882a593Smuzhiyun 		ret = env_attr_lookup(flags_list, name, flags);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (ret != 0)
298*4882a593Smuzhiyun 		/* if not found in the env, look in the static list */
299*4882a593Smuzhiyun 		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	return ret;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun #ifdef USE_HOSTCC /* Functions only used from tools/env */
305*4882a593Smuzhiyun /*
306*4882a593Smuzhiyun  * Look up any flags directly from the .flags variable and the static list
307*4882a593Smuzhiyun  * and convert them to the vartype enum.
308*4882a593Smuzhiyun  */
env_flags_get_type(const char * name)309*4882a593Smuzhiyun enum env_flags_vartype env_flags_get_type(const char *name)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	const char *flags_list = env_get(ENV_FLAGS_VAR);
312*4882a593Smuzhiyun 	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (env_flags_lookup(flags_list, name, flags))
315*4882a593Smuzhiyun 		return env_flags_vartype_string;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
318*4882a593Smuzhiyun 		return env_flags_vartype_string;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	return env_flags_parse_vartype(flags);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun /*
324*4882a593Smuzhiyun  * Look up the access of a variable directly from the .flags var.
325*4882a593Smuzhiyun  */
env_flags_get_varaccess(const char * name)326*4882a593Smuzhiyun enum env_flags_varaccess env_flags_get_varaccess(const char *name)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	const char *flags_list = env_get(ENV_FLAGS_VAR);
329*4882a593Smuzhiyun 	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	if (env_flags_lookup(flags_list, name, flags))
332*4882a593Smuzhiyun 		return env_flags_varaccess_any;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
335*4882a593Smuzhiyun 		return env_flags_varaccess_any;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	return env_flags_parse_varaccess(flags);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun  * Validate that the proposed new value for "name" is valid according to the
342*4882a593Smuzhiyun  * defined flags for that variable, if any.
343*4882a593Smuzhiyun  */
env_flags_validate_type(const char * name,const char * value)344*4882a593Smuzhiyun int env_flags_validate_type(const char *name, const char *value)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	enum env_flags_vartype type;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	if (value == NULL)
349*4882a593Smuzhiyun 		return 0;
350*4882a593Smuzhiyun 	type = env_flags_get_type(name);
351*4882a593Smuzhiyun 	if (_env_flags_validate_type(value, type) < 0) {
352*4882a593Smuzhiyun 		printf("## Error: flags type check failure for "
353*4882a593Smuzhiyun 			"\"%s\" <= \"%s\" (type: %c)\n",
354*4882a593Smuzhiyun 			name, value, env_flags_vartype_rep[type]);
355*4882a593Smuzhiyun 		return -1;
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun 	return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun /*
361*4882a593Smuzhiyun  * Validate that the proposed access to variable "name" is valid according to
362*4882a593Smuzhiyun  * the defined flags for that variable, if any.
363*4882a593Smuzhiyun  */
env_flags_validate_varaccess(const char * name,int check_mask)364*4882a593Smuzhiyun int env_flags_validate_varaccess(const char *name, int check_mask)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	enum env_flags_varaccess access;
367*4882a593Smuzhiyun 	int access_mask;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	access = env_flags_get_varaccess(name);
370*4882a593Smuzhiyun 	access_mask = env_flags_varaccess_mask[access];
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	return (check_mask & access_mask) != 0;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun /*
376*4882a593Smuzhiyun  * Validate the parameters to "env set" directly
377*4882a593Smuzhiyun  */
env_flags_validate_env_set_params(char * name,char * const val[],int count)378*4882a593Smuzhiyun int env_flags_validate_env_set_params(char *name, char * const val[], int count)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	if ((count >= 1) && val[0] != NULL) {
381*4882a593Smuzhiyun 		enum env_flags_vartype type = env_flags_get_type(name);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		/*
384*4882a593Smuzhiyun 		 * we don't currently check types that need more than
385*4882a593Smuzhiyun 		 * one argument
386*4882a593Smuzhiyun 		 */
387*4882a593Smuzhiyun 		if (type != env_flags_vartype_string && count > 1) {
388*4882a593Smuzhiyun 			printf("## Error: too many parameters for setting \"%s\"\n",
389*4882a593Smuzhiyun 			       name);
390*4882a593Smuzhiyun 			return -1;
391*4882a593Smuzhiyun 		}
392*4882a593Smuzhiyun 		return env_flags_validate_type(name, val[0]);
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 	/* ok */
395*4882a593Smuzhiyun 	return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun #else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun /*
401*4882a593Smuzhiyun  * Parse the flag charachters from the .flags attribute list into the binary
402*4882a593Smuzhiyun  * form to be stored in the environment entry->flags field.
403*4882a593Smuzhiyun  */
env_parse_flags_to_bin(const char * flags)404*4882a593Smuzhiyun static int env_parse_flags_to_bin(const char *flags)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	int binflags;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
409*4882a593Smuzhiyun 	binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)];
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	return binflags;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun static int first_call = 1;
415*4882a593Smuzhiyun static const char *flags_list;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun /*
418*4882a593Smuzhiyun  * Look for possible flags for a newly added variable
419*4882a593Smuzhiyun  * This is called specifically when the variable did not exist in the hash
420*4882a593Smuzhiyun  * previously, so the blanket update did not find this variable.
421*4882a593Smuzhiyun  */
env_flags_init(ENTRY * var_entry)422*4882a593Smuzhiyun void env_flags_init(ENTRY *var_entry)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	const char *var_name = var_entry->key;
425*4882a593Smuzhiyun 	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = "";
426*4882a593Smuzhiyun 	int ret = 1;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	if (first_call) {
429*4882a593Smuzhiyun 		flags_list = env_get(ENV_FLAGS_VAR);
430*4882a593Smuzhiyun 		first_call = 0;
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 	/* look in the ".flags" and static for a reference to this variable */
433*4882a593Smuzhiyun 	ret = env_flags_lookup(flags_list, var_name, flags);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	/* if any flags were found, set the binary form to the entry */
436*4882a593Smuzhiyun 	if (!ret && strlen(flags))
437*4882a593Smuzhiyun 		var_entry->flags = env_parse_flags_to_bin(flags);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun /*
441*4882a593Smuzhiyun  * Called on each existing env var prior to the blanket update since removing
442*4882a593Smuzhiyun  * a flag in the flag list should remove its flags.
443*4882a593Smuzhiyun  */
clear_flags(ENTRY * entry)444*4882a593Smuzhiyun static int clear_flags(ENTRY *entry)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	entry->flags = 0;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return 0;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun /*
452*4882a593Smuzhiyun  * Call for each element in the list that defines flags for a variable
453*4882a593Smuzhiyun  */
set_flags(const char * name,const char * value,void * priv)454*4882a593Smuzhiyun static int set_flags(const char *name, const char *value, void *priv)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	ENTRY e, *ep;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	e.key	= name;
459*4882a593Smuzhiyun 	e.data	= NULL;
460*4882a593Smuzhiyun 	e.callback = NULL;
461*4882a593Smuzhiyun 	hsearch_r(e, FIND, &ep, &env_htab, 0);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/* does the env variable actually exist? */
464*4882a593Smuzhiyun 	if (ep != NULL) {
465*4882a593Smuzhiyun 		/* the flag list is empty, so clear the flags */
466*4882a593Smuzhiyun 		if (value == NULL || strlen(value) == 0)
467*4882a593Smuzhiyun 			ep->flags = 0;
468*4882a593Smuzhiyun 		else
469*4882a593Smuzhiyun 			/* assign the requested flags */
470*4882a593Smuzhiyun 			ep->flags = env_parse_flags_to_bin(value);
471*4882a593Smuzhiyun 	}
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
on_flags(const char * name,const char * value,enum env_op op,int flags)476*4882a593Smuzhiyun static int on_flags(const char *name, const char *value, enum env_op op,
477*4882a593Smuzhiyun 	int flags)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	/* remove all flags */
480*4882a593Smuzhiyun 	hwalk_r(&env_htab, clear_flags);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	/* configure any static flags */
483*4882a593Smuzhiyun 	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags, NULL);
484*4882a593Smuzhiyun 	/* configure any dynamic flags */
485*4882a593Smuzhiyun 	env_attr_walk(value, set_flags, NULL);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun U_BOOT_ENV_CALLBACK(flags, on_flags);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun /*
492*4882a593Smuzhiyun  * Perform consistency checking before creating, overwriting, or deleting an
493*4882a593Smuzhiyun  * environment variable. Called as a callback function by hsearch_r() and
494*4882a593Smuzhiyun  * hdelete_r(). Returns 0 in case of success, 1 in case of failure.
495*4882a593Smuzhiyun  * When (flag & H_FORCE) is set, do not print out any error message and force
496*4882a593Smuzhiyun  * overwriting of write-once variables.
497*4882a593Smuzhiyun  */
498*4882a593Smuzhiyun 
env_flags_validate(const ENTRY * item,const char * newval,enum env_op op,int flag)499*4882a593Smuzhiyun int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
500*4882a593Smuzhiyun 	int flag)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun 	const char *name;
503*4882a593Smuzhiyun 	const char *oldval = NULL;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (op != env_op_create)
506*4882a593Smuzhiyun 		oldval = item->data;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	name = item->key;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	/* Default value for NULL to protect string-manipulating functions */
511*4882a593Smuzhiyun 	newval = newval ? : "";
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	/* validate the value to match the variable type */
514*4882a593Smuzhiyun 	if (op != env_op_delete) {
515*4882a593Smuzhiyun 		enum env_flags_vartype type = (enum env_flags_vartype)
516*4882a593Smuzhiyun 			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 		if (_env_flags_validate_type(newval, type) < 0) {
519*4882a593Smuzhiyun 			printf("## Error: flags type check failure for "
520*4882a593Smuzhiyun 				"\"%s\" <= \"%s\" (type: %c)\n",
521*4882a593Smuzhiyun 				name, newval, env_flags_vartype_rep[type]);
522*4882a593Smuzhiyun 			return -1;
523*4882a593Smuzhiyun 		}
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	/* check for access permission */
527*4882a593Smuzhiyun #ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
528*4882a593Smuzhiyun 	if (flag & H_FORCE)
529*4882a593Smuzhiyun 		return 0;
530*4882a593Smuzhiyun #endif
531*4882a593Smuzhiyun 	switch (op) {
532*4882a593Smuzhiyun 	case env_op_delete:
533*4882a593Smuzhiyun 		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
534*4882a593Smuzhiyun 			printf("## Error: Can't delete \"%s\"\n", name);
535*4882a593Smuzhiyun 			return 1;
536*4882a593Smuzhiyun 		}
537*4882a593Smuzhiyun 		break;
538*4882a593Smuzhiyun 	case env_op_overwrite:
539*4882a593Smuzhiyun 		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
540*4882a593Smuzhiyun 			printf("## Error: Can't overwrite \"%s\"\n", name);
541*4882a593Smuzhiyun 			return 1;
542*4882a593Smuzhiyun 		} else if (item->flags &
543*4882a593Smuzhiyun 		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
544*4882a593Smuzhiyun 			const char *defval = env_get_default(name);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 			if (defval == NULL)
547*4882a593Smuzhiyun 				defval = "";
548*4882a593Smuzhiyun 			printf("oldval: %s  defval: %s\n", oldval, defval);
549*4882a593Smuzhiyun 			if (strcmp(oldval, defval) != 0) {
550*4882a593Smuzhiyun 				printf("## Error: Can't overwrite \"%s\"\n",
551*4882a593Smuzhiyun 					name);
552*4882a593Smuzhiyun 				return 1;
553*4882a593Smuzhiyun 			}
554*4882a593Smuzhiyun 		}
555*4882a593Smuzhiyun 		break;
556*4882a593Smuzhiyun 	case env_op_create:
557*4882a593Smuzhiyun 		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
558*4882a593Smuzhiyun 			printf("## Error: Can't create \"%s\"\n", name);
559*4882a593Smuzhiyun 			return 1;
560*4882a593Smuzhiyun 		}
561*4882a593Smuzhiyun 		break;
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	return 0;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun #endif
568