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