1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Environment variable subroutines		File: env_subr.c
5    *
6    *  This module contains routines to muck with environment variables
7    *  (manage the list, read/write to nvram, etc.)
8    *
9    *  Author:  Mitch Lichtenberg
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48#include "cfe.h"
49
50#include "env_subr.h"
51#include "nvram_subr.h"
52
53/*  *********************************************************************
54    *  Types
55    ********************************************************************* */
56
57typedef struct cfe_envvar_s {
58    queue_t qb;
59    int flags;
60    char *name;
61    char *value;
62    /* name and value go here */
63} cfe_envvar_t;
64
65/*  *********************************************************************
66    *  Globals
67    ********************************************************************* */
68
69queue_t env_envvars = {&env_envvars,&env_envvars};
70extern unsigned int cfe_startflags;
71
72char *varchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
73                        "abcdefghijklmnopqrstuvwxyz"
74                        "0123456789_?";
75
76/*  *********************************************************************
77    *  env_findenv(name)
78    *
79    *  Locate an environment variable in the in-memory list
80    *
81    *  Input parameters:
82    *  	   name - name of env var to find
83    *
84    *  Return value:
85    *  	   cfe_envvar_t pointer, or NULL if not found
86    ********************************************************************* */
87
88static cfe_envvar_t *env_findenv(const char *name)
89{
90    queue_t *qb;
91    cfe_envvar_t *env;
92
93    for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) {
94	env = (cfe_envvar_t *) qb;
95	if (strcmp(env->name,name) == 0) break;
96	}
97
98    if (qb == &env_envvars) return NULL;
99
100    return (cfe_envvar_t *) qb;
101
102}
103
104/*  *********************************************************************
105    *  env_enum(idx,name,namelen,val,vallen)
106    *
107    *  Enumerate environment variables.  This routine locates
108    *  the nth environment variable and copies its name and value
109    *  to user buffers.
110    *
111    *  The namelen and vallen variables must be preinitialized to
112    *  the maximum size of the output buffer.
113    *
114    *  Input parameters:
115    *  	   idx - variable index to find (starting with zero)
116    *  	   name,namelen - name buffer and length
117    *  	   val,vallen - value buffer and length
118    *
119    *  Return value:
120    *  	   0 if ok
121    *  	   else error code
122    ********************************************************************* */
123
124int env_enum(int idx,char *name,int *namelen,char *val,int *vallen)
125{
126    queue_t *qb;
127    cfe_envvar_t *env;
128
129    for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) {
130	if (idx == 0) break;
131	idx--;
132	}
133
134    if (qb == &env_envvars) return CFE_ERR_ENVNOTFOUND;
135    env = (cfe_envvar_t *) qb;
136
137    *namelen = xstrncpy(name,env->name,*namelen);
138    *vallen  = xstrncpy(val,env->value,*vallen);
139
140    return 0;
141
142}
143
144/*  *********************************************************************
145    *  env_envtype(name)
146    *
147    *  Return the type of the environment variable
148    *
149    *  Input parameters:
150    *  	   name - name of environment variable
151    *
152    *  Return value:
153    *  	   flags, or <0 if error occured
154    ********************************************************************* */
155int env_envtype(const char *name)
156{
157    cfe_envvar_t *env;
158
159    env = env_findenv(name);
160
161    if (env) {
162	return env->flags;
163	}
164
165    return CFE_ERR_ENVNOTFOUND;
166}
167
168/*  *********************************************************************
169    *  env_setflags(name,flags)
170    *
171    *  Set the flags of a variable
172    *
173    *  Input parameters:
174    *  	   name - name of env var
175    *	   flags - flags for variable
176    *
177    *  Return value:
178    *  	   0 if ok
179    *	   else error code
180    ********************************************************************* */
181
182int env_setflags(const char *name, int flags)
183{
184    cfe_envvar_t *env;
185
186    env = env_findenv(name);
187
188    if (env == NULL) {
189	return CFE_ERR;
190	}
191
192    env->flags = (flags & ENV_FLG_MASK);
193
194    return 0;
195
196}
197
198/*  *********************************************************************
199    *  env_delenv(name)
200    *
201    *  Delete an environment variable
202    *
203    *  Input parameters:
204    *  	   name - environment variable to delete
205    *
206    *  Return value:
207    *  	   0 if ok
208    *  	   else error code
209    ********************************************************************* */
210
211int env_delenv(const char *name)
212{
213    cfe_envvar_t *env;
214
215    env = env_findenv(name);
216
217    if (!env) return 0;
218
219    if (!(env->flags & ENV_FLG_READONLY)) {
220	q_dequeue((queue_t *) env);
221	KFREE(env);
222	return 0;
223	}
224
225    return CFE_ERR_ENVNOTFOUND;
226}
227
228/*  *********************************************************************
229    *  env_getenv(name)
230    *
231    *  Retrieve the value of an environment variable
232    *
233    *  Input parameters:
234    *  	   name - name of environment variable to find
235    *
236    *  Return value:
237    *  	   value, or NULL if variable is not found
238    ********************************************************************* */
239
240char *env_getenv(const char *name)
241{
242    cfe_envvar_t *env;
243
244    env = env_findenv(name);
245
246    if (env) {
247	return env->value;
248	}
249
250    return NULL;
251}
252
253
254/*  *********************************************************************
255    *  env_setenv(name,value,flags)
256    *
257    *  Set the value of an environment variable
258    *
259    *  Input parameters:
260    *  	   name - name of variable
261    *  	   value - value of variable
262    *  	   flags - flags for variable (ENV_FLG_xxx)
263    *
264    *  Return value:
265    *  	   0 if ok
266    *  	   else error code
267    ********************************************************************* */
268
269int env_setenv(const char *name,char *value,int flags)
270{
271    cfe_envvar_t *env;
272    int namelen;
273
274    env = env_findenv(name);
275    if (env) {
276	if (!(flags & ENV_FLG_ADMIN)) {
277	    if (env->flags & ENV_FLG_READONLY) return CFE_ERR_ENVREADONLY;
278	    }
279	q_dequeue((queue_t *) env);
280	KFREE(env);
281	}
282
283    namelen = strlen(name);
284
285    env = KMALLOC(sizeof(cfe_envvar_t) + namelen + 1 + strlen(value) + 1,0);
286    if (!env) return CFE_ERR_NOMEM;
287
288    env->name = (char *) (env+1);
289    env->value = env->name + namelen + 1;
290    env->flags = (flags & ENV_FLG_MASK);
291
292    strcpy(env->name,name);
293    strcpy(env->value,value);
294
295    q_enqueue(&env_envvars,(queue_t *) env);
296
297    return 0;
298}
299
300/*  *********************************************************************
301    *  env_load()
302    *
303    *  Load the environment from the NVRAM device.
304    *
305    *  Input parameters:
306    *  	   nothing
307    *
308    *  Return value:
309    *  	   0 if ok
310    *  	   else error code
311    ********************************************************************* */
312
313
314int env_load(void)
315{
316    int size;
317    unsigned char *buffer;
318    unsigned char *ptr;
319    unsigned char *envval;
320    unsigned int reclen;
321    unsigned int rectype;
322    int offset;
323    int flg;
324    int retval = -1;
325    char valuestr[256];
326
327    /*
328     * If in 'safe mode', don't read the environment the first time.
329     */
330
331    if (cfe_startflags & CFE_INIT_SAFE) {
332	cfe_startflags &= ~CFE_INIT_SAFE;
333	return 0;
334	}
335
336    flg = nvram_open();
337    if (flg < 0) return flg;
338
339    size = nvram_getsize();
340    buffer = KMALLOC(size,0);
341
342    if (buffer == NULL) return CFE_ERR_NOMEM;
343
344    ptr = buffer;
345    offset = 0;
346
347    /* Read the record type and length */
348    if (nvram_read(ptr,offset,1) != 1) {
349	retval = CFE_ERR_IOERR;
350	goto error;
351	}
352
353    while ((*ptr != ENV_TLV_TYPE_END)  && (size > 1)) {
354
355	/* Adjust pointer for TLV type */
356	rectype = *(ptr);
357	offset++;
358	size--;
359
360	/*
361	 * Read the length.  It can be either 1 or 2 bytes
362	 * depending on the code
363	 */
364	if (rectype & ENV_LENGTH_8BITS) {
365	    /* Read the record type and length - 8 bits */
366	    if (nvram_read(ptr,offset,1) != 1) {
367		retval = CFE_ERR_IOERR;
368		goto error;
369		}
370	    reclen = *(ptr);
371	    size--;
372	    offset++;
373	    }
374	else {
375	    /* Read the record type and length - 16 bits, MSB first */
376	    if (nvram_read(ptr,offset,2) != 2) {
377		retval = CFE_ERR_IOERR;
378		goto error;
379		}
380	    reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
381	    size -= 2;
382	    offset += 2;
383	    }
384
385	if (reclen > size) break;	/* should not happen, bad NVRAM */
386
387	switch (rectype) {
388	    case ENV_TLV_TYPE_ENV:
389		/* Read the TLV data */
390		if (nvram_read(ptr,offset,reclen) != reclen) goto error;
391		flg = *ptr++;
392		envval = (unsigned char *) strnchr((char *)ptr,'=',(reclen-1));
393		if (envval) {
394		    *envval++ = '\0';
395		    memcpy(valuestr,envval,(reclen-1)-(envval-ptr));
396		    valuestr[(reclen-1)-(envval-ptr)] = '\0';
397		    env_setenv((char *)ptr,valuestr,flg);
398		    }
399		break;
400
401	    default:
402		/* Unknown TLV type, skip it. */
403		break;
404	    }
405
406	/*
407	 * Advance to next TLV
408	 */
409
410	size -= (int)reclen;
411	offset += reclen;
412
413	/* Read the next record type */
414	ptr = buffer;
415	if (nvram_read(ptr,offset,1) != 1) goto error;
416	}
417
418    retval = 0;		/* success! */
419
420error:
421    KFREE(buffer);
422    nvram_close();
423
424    return retval;
425
426}
427
428
429/*  *********************************************************************
430    *  env_save()
431    *
432    *  Write the environment to the NVRAM device.
433    *
434    *  Input parameters:
435    *  	   nothing
436    *
437    *  Return value:
438    *  	   0 if ok, else error code
439    ********************************************************************* */
440
441int env_save(void)
442{
443    int size;
444    unsigned char *buffer;
445    unsigned char *buffer_end;
446    unsigned char *ptr;
447    queue_t *qb;
448    cfe_envvar_t *env;
449    int namelen;
450    int valuelen;
451    int flg;
452
453    flg = nvram_open();
454    if (flg < 0) return flg;
455
456    nvram_erase();
457
458    size = nvram_getsize();
459    buffer = KMALLOC(size,0);
460
461    if (buffer == NULL) return CFE_ERR_NOMEM;
462
463    buffer_end = buffer + size;
464
465    ptr = buffer;
466
467    for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) {
468	env = (cfe_envvar_t *) qb;
469
470	if (env->flags & (ENV_FLG_BUILTIN)) continue;
471
472	namelen = strlen(env->name);
473	valuelen = strlen(env->value);
474
475	if ((ptr + 2 + namelen + valuelen + 1 + 1 + 1) > buffer_end) break;
476
477	*ptr++ = ENV_TLV_TYPE_ENV;		/* TLV record type */
478	*ptr++ = (namelen + valuelen + 1 + 1);	/* TLV record length */
479
480	*ptr++ = (unsigned char)env->flags;
481	memcpy(ptr,env->name,namelen);		/* TLV record data */
482	ptr += namelen;
483	*ptr++ = '=';
484	memcpy(ptr,env->value,valuelen);
485	ptr += valuelen;
486
487	}
488
489    *ptr++ = ENV_TLV_TYPE_END;
490
491    size = nvram_write(buffer,0,ptr-buffer);
492
493    KFREE(buffer);
494
495    nvram_close();
496
497    return (size == (ptr-buffer)) ? 0 : CFE_ERR_IOERR;
498}
499