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