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 (mpl@broadcom.com)
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 "lib_types.h"
49#include "lib_string.h"
50#include "lib_queue.h"
51#include "lib_malloc.h"
52#include "lib_printf.h"
53
54#include "env_subr.h"
55#include "nvram_subr.h"
56
57#include "cfe_error.h"
58#include "cfe.h"
59
60#ifdef EB332
61extern void setenv (char *e, char *v, int rewrite);
62#endif
63/*  *********************************************************************
64    *  Types
65    ********************************************************************* */
66
67typedef struct cfe_envvar_s {
68    queue_t qb;
69    int flags;
70    char *name;
71    char *value;
72    /* name and value go here */
73} cfe_envvar_t;
74
75/*  *********************************************************************
76    *  Globals
77    ********************************************************************* */
78
79queue_t env_envvars = {&env_envvars,&env_envvars};
80extern unsigned int cfe_startflags;
81
82/*  *********************************************************************
83    *  env_findenv(name)
84    *
85    *  Locate an environment variable in the in-memory list
86    *
87    *  Input parameters:
88    *  	   name - name of env var to find
89    *
90    *  Return value:
91    *  	   cfe_envvar_t pointer, or NULL if not found
92    ********************************************************************* */
93
94static cfe_envvar_t *env_findenv(const char *name)
95{
96    queue_t *qb;
97    cfe_envvar_t *env;
98
99    for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) {
100	env = (cfe_envvar_t *) qb;
101	if (strcmp(env->name,name) == 0) break;
102	}
103
104    if (qb == &env_envvars) return NULL;
105
106    return (cfe_envvar_t *) qb;
107
108}
109
110/*  *********************************************************************
111    *  env_enum(idx,name,namelen,val,vallen)
112    *
113    *  Enumerate environment variables.  This routine locates
114    *  the nth environment variable and copies its name and value
115    *  to user buffers.
116    *
117    *  The namelen and vallen variables must be preinitialized to
118    *  the maximum size of the output buffer.
119    *
120    *  Input parameters:
121    *  	   idx - variable index to find (starting with zero)
122    *  	   name,namelen - name buffer and length
123    *  	   val,vallen - value buffer and length
124    *
125    *  Return value:
126    *  	   0 if ok
127    *  	   else error code
128    ********************************************************************* */
129
130int env_enum(int idx,char *name,int *namelen,char *val,int *vallen)
131{
132    queue_t *qb;
133    cfe_envvar_t *env;
134
135    for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) {
136	if (idx == 0) break;
137	idx--;
138	}
139
140    if (qb == &env_envvars) return CFE_ERR_ENVNOTFOUND;
141    env = (cfe_envvar_t *) qb;
142
143    *namelen = xstrncpy(name,env->name,*namelen);
144    *vallen  = xstrncpy(val,env->value,*vallen);
145
146    return 0;
147
148}
149
150/*  *********************************************************************
151    *  env_envtype(name)
152    *
153    *  Return the type of the environment variable
154    *
155    *  Input parameters:
156    *  	   name - name of environment variable
157    *
158    *  Return value:
159    *  	   flags, or <0 if error occured
160    ********************************************************************* */
161int env_envtype(const char *name)
162{
163    cfe_envvar_t *env;
164
165    env = env_findenv(name);
166
167    if (env) {
168	return env->flags;
169	}
170
171    return CFE_ERR_ENVNOTFOUND;
172}
173
174
175
176/*  *********************************************************************
177    *  env_delenv(name)
178    *
179    *  Delete an environment variable
180    *
181    *  Input parameters:
182    *  	   name - environment variable to delete
183    *
184    *  Return value:
185    *  	   0 if ok
186    *  	   else error code
187    ********************************************************************* */
188
189int env_delenv(const char *name)
190{
191    cfe_envvar_t *env;
192
193    env = env_findenv(name);
194
195    if (!env) return 0;
196
197    if (!(env->flags & ENV_FLG_READONLY)) {
198	q_dequeue((queue_t *) env);
199	KFREE(env);
200	return 0;
201	}
202
203    return CFE_ERR_ENVNOTFOUND;
204}
205
206/*  *********************************************************************
207    *  env_getenv(name)
208    *
209    *  Retrieve the value of an environment variable
210    *
211    *  Input parameters:
212    *  	   name - name of environment variable to find
213    *
214    *  Return value:
215    *  	   value, or NULL if variable is not found
216    ********************************************************************* */
217
218char *env_getenv(const char *name)
219{
220    cfe_envvar_t *env;
221
222    env = env_findenv(name);
223
224    if (env) {
225	return env->value;
226	}
227
228    return NULL;
229}
230
231
232/*  *********************************************************************
233    *  env_setenv(name,value,flags)
234    *
235    *  Set the value of an environment variable
236    *
237    *  Input parameters:
238    *  	   name - name of variable
239    *  	   value - value of variable
240    *  	   flags - flags for variable (ENV_FLG_xxx)
241    *
242    *  Return value:
243    *  	   0 if ok
244    *  	   else error code
245    ********************************************************************* */
246
247int env_setenv(const char *name,char *value,int flags)
248{
249    cfe_envvar_t *env;
250    int namelen;
251
252    env = env_findenv(name);
253    if (env) {
254	if (!(flags & ENV_FLG_ADMIN)) {
255	    if (env->flags & ENV_FLG_READONLY) return CFE_ERR_ENVREADONLY;
256	    }
257	q_dequeue((queue_t *) env);
258	KFREE(env);
259	}
260
261    namelen = strlen(name);
262
263    env = KMALLOC(sizeof(cfe_envvar_t) + namelen + 1 + strlen(value) + 1,0);
264    if (!env) return CFE_ERR_NOMEM;
265
266    env->name = (char *) (env+1);
267    env->value = env->name + namelen + 1;
268    env->flags = (flags & ENV_FLG_MASK);
269
270    strcpy(env->name,name);
271    strcpy(env->value,value);
272
273    q_enqueue(&env_envvars,(queue_t *) env);
274
275    return 0;
276}
277
278
279/*  *********************************************************************
280    *  env_load()
281    *
282    *  Load the environment from the NVRAM device.
283    *
284    *  Input parameters:
285    *  	   nothing
286    *
287    *  Return value:
288    *  	   0 if ok
289    *  	   else error code
290    ********************************************************************* */
291
292
293int env_load(void)
294{
295    int size;
296    unsigned char *buffer;
297    unsigned char *ptr;
298    unsigned char *envval;
299    unsigned int reclen;
300    unsigned int rectype;
301    int offset;
302    int flg;
303    int retval = -1;
304    char valuestr[256];
305
306    /*
307     * If in 'safe mode', don't read the environment the first time.
308     */
309
310    if (cfe_startflags & CFE_INIT_SAFE) {
311	cfe_startflags &= ~CFE_INIT_SAFE;
312	return 0;
313	}
314
315    flg = nvram_open();
316    if (flg < 0) return flg;
317
318    size = nvram_getsize();
319    buffer = KMALLOC(size,0);
320
321    if (buffer == NULL) return CFE_ERR_NOMEM;
322
323    ptr = buffer;
324    offset = 0;
325
326    /* Read the record type and length */
327    if (nvram_read(ptr,offset,1) != 1) {
328	retval = CFE_ERR_IOERR;
329	goto error;
330	}
331
332    while ((*ptr != ENV_TLV_TYPE_END)  && (size > 1)) {
333
334	/* Adjust pointer for TLV type */
335	rectype = *(ptr);
336	offset++;
337	size--;
338
339	/*
340	 * Read the length.  It can be either 1 or 2 bytes
341	 * depending on the code
342	 */
343	if (rectype & ENV_LENGTH_8BITS) {
344	    /* Read the record type and length - 8 bits */
345	    if (nvram_read(ptr,offset,1) != 1) {
346		retval = CFE_ERR_IOERR;
347		goto error;
348		}
349	    reclen = *(ptr);
350	    size--;
351	    offset++;
352	    }
353	else {
354	    /* Read the record type and length - 16 bits, MSB first */
355	    if (nvram_read(ptr,offset,2) != 2) {
356		retval = CFE_ERR_IOERR;
357		goto error;
358		}
359	    reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
360	    size -= 2;
361	    offset += 2;
362	    }
363
364	if (reclen > size) break;	/* should not happen, bad NVRAM */
365
366	switch (rectype) {
367	    case ENV_TLV_TYPE_ENV:
368		/* Read the TLV data */
369		if (nvram_read(ptr,offset,reclen) != reclen) goto error;
370		flg = *ptr++;
371		envval = (unsigned char *) strnchr(ptr,'=',(reclen-1));
372		if (envval) {
373		    *envval++ = '\0';
374		    memcpy(valuestr,envval,(reclen-1)-(envval-ptr));
375		    valuestr[(reclen-1)-(envval-ptr)] = '\0';
376		    env_setenv(ptr,valuestr,flg);
377		    }
378		break;
379
380	    default:
381		/* Unknown TLV type, skip it. */
382		break;
383	    }
384
385	/*
386	 * Advance to next TLV
387	 */
388
389	size -= (int)reclen;
390	offset += reclen;
391
392	/* Read the next record type */
393	ptr = buffer;
394	if (nvram_read(ptr,offset,1) != 1) goto error;
395	}
396
397    retval = 0;		/* success! */
398
399error:
400    KFREE(buffer);
401    nvram_close();
402
403    return retval;
404
405}
406
407
408/*  *********************************************************************
409    *  env_save()
410    *
411    *  Write the environment to the NVRAM device.
412    *
413    *  Input parameters:
414    *  	   nothing
415    *
416    *  Return value:
417    *  	   0 if ok, else error code
418    ********************************************************************* */
419
420int env_save(void)
421{
422    int size;
423    unsigned char *buffer;
424    unsigned char *buffer_end;
425    unsigned char *ptr;
426    queue_t *qb;
427    cfe_envvar_t *env;
428    int namelen;
429    int valuelen;
430    int flg;
431
432    flg = nvram_open();
433    if (flg < 0) return flg;
434
435    nvram_erase();
436
437    size = nvram_getsize();
438    buffer = KMALLOC(size,0);
439
440    if (buffer == NULL) return CFE_ERR_NOMEM;
441
442    buffer_end = buffer + size;
443
444    ptr = buffer;
445
446    for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) {
447	env = (cfe_envvar_t *) qb;
448
449	if (env->flags & (ENV_FLG_BUILTIN)) continue;
450
451	namelen = strlen(env->name);
452	valuelen = strlen(env->value);
453
454	if ((ptr + 2 + namelen + valuelen + 1 + 1 + 1) > buffer_end) break;
455
456	*ptr++ = ENV_TLV_TYPE_ENV;		/* TLV record type */
457	*ptr++ = (namelen + valuelen + 1 + 1);	/* TLV record length */
458
459	*ptr++ = (unsigned char)env->flags;
460	memcpy(ptr,env->name,namelen);		/* TLV record data */
461	ptr += namelen;
462	*ptr++ = '=';
463	memcpy(ptr,env->value,valuelen);
464	ptr += valuelen;
465#ifdef EB332
466	setenv(env->name, env->value, 1);
467#endif
468
469	}
470
471    *ptr++ = ENV_TLV_TYPE_END;
472
473    size = nvram_write(buffer,0,ptr-buffer);
474
475    KFREE(buffer);
476
477    nvram_close();
478
479    return (size == (ptr-buffer)) ? 0 : CFE_ERR_IOERR;
480}
481