+++ /dev/null
-/*
- * NVRAM variable manipulation (common)
- *
- * $Copyright Open Broadcom Corporation$
- *
- * NVRAM emulation interface
- *
- * $Id:$
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <typedefs.h>
-#include <bcmendian.h>
-#include <bcmnvram.h>
-#include <bcmutils.h>
-
-/* for file locking */
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#define LOCK_FILE "/var/nvram.lock"
-#define MAX_LOCK_WAIT 10
-
-/* for mmap */
-#include <sys/mman.h>
-#define NVRAM_FILE "/var/nvram"
-
-/* internal structure */
-struct nvram_header nv_header = { 0x48534C46, 0x14, 0x52565344, 0, 0xffffffff };
-static struct nvram_tuple * nvram_hash[32] = { NULL };
-static struct nvram_tuple * nvram_dead = NULL;
-static struct nvram_tuple * nvram_deleted = NULL;
-
-/* declaration */
-char * _nvram_get(const char *name);
-int _nvram_set(const char *name, const char *value);
-int _nvram_unset(const char *name);
-int _nvram_getall(char *buf, int count);
-int _nvram_commit(struct nvram_header *header);
-int _nvram_init(void);
-void _nvram_exit(void);
-int nvram_getall(char *buf, int count);
-int _nvram_refresh(const char *name, const char *value);
-
-static int _lock();
-static int _unlock();
-static int _nvram_lock();
-static int _nvram_unlock();
-static void* _nvram_mmap_alloc(int size);
-static void* _nvram_mmap_free(void *va, int size);
-
-#define _MALLOC_(x) calloc(x, sizeof(char))
-#define _MFREE_(buf, size) free(buf)
-
-#define _NVRAM_MALLOC_(x) _nvram_mmap_alloc(x)
-#define _NVRAM_MFREE_(buf, size) _nvram_mmap_free(buf,size)
-
-static int nvram_inited=0;
-
-#define DBG_NVRAM_SET 0x00000001
-#define DBG_NVRAM_GET 0x00000002
-#define DBG_NVRAM_GETALL 0x00000004
-#define DBG_NVRAM_UNSET 0x00000008
-#define DBG_NVRAM_COMMIT 0x00000010
-#define DBG_NVRAM_UPDATE 0x00000020
-#define DBG_NVRAM_INFO 0x00000040
-#define DBG_NVRAM_ERROR 0x00000080
-
-
-#ifdef BCMDBG
-#define DBG_SET(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_SET) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_GET(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_GET) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_GETALL(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_GETALL) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_UNSET(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_UNSET) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_COMMIT(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_COMMIT) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_UPDATE(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_UPDATE) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_INFO(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_INFO) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#define DBG_ERROR(fmt, arg...) \
- do { if (debug_nvram_level & DBG_NVRAM_ERROR) \
- printf("%s: "fmt , __FUNCTION__ , ##arg); } while(0)
-
-#else
-#define DBG_SET(fmt, arg...)
-#define DBG_GET(fmt, arg...)
-#define DBG_GETALL(fmt, arg...)
-#define DBG_UNSET(fmt, arg...)
-#define DBG_COMMIT(fmt, arg...)
-#define DBG_UPDATE(fmt, arg...)
-#define DBG_INFO(fmt, arg...)
-#define DBG_ERROR(fmt, arg...)
-#endif
-
-static int debug_nvram_level = DBG_NVRAM_ERROR;
-
-static int _lock()
-{
- int fd;
- fd = open(LOCK_FILE,O_WRONLY|O_CREAT|O_EXCL,0644);
- if (fd < 0 && errno == EEXIST) {
- DBG_INFO("%s is already locked\n",LOCK_FILE);
- return 0;
- } else if (fd < 0){
- DBG_ERROR("unexpected error checking lock");
- return 0;
- }
- DBG_INFO(" nvram : %s created\n",LOCK_FILE);
- close(fd);
- return 1;
-}
-
-static int _unlock()
-{
- if (unlink(LOCK_FILE) < 0) {
- DBG_ERROR("cannot remove lock file");
- return 0;
- }
- DBG_INFO(" nvram : %s deleted\n",LOCK_FILE);
- return 1;
-}
-
-static int _nvram_lock()
-{
- int i=0;
- while (!_lock() && (i++ < MAX_LOCK_WAIT)) {
- usleep(500000);
- }
- if(i >= MAX_LOCK_WAIT)
- return 0;
- else
- return 1;
-}
-static int _nvram_unlock()
-{
- int i=0;
- while (!_unlock() && (i++ < MAX_LOCK_WAIT)) {
- usleep(500000);
- }
- if(i > MAX_LOCK_WAIT)
- return 0;
- else
- return 1;
-}
-
-
-static void* _nvram_mmap_alloc(int size)
-{
- int fd;
- void *va=NULL;
-
- if((fd = open(NVRAM_FILE, O_CREAT|O_SYNC|O_RDWR, 0644)) < 0) {
- DBG_ERROR(" nvram: file open error");
- return 0;
- }
-
- ftruncate(fd,size);
-
- va = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fd, 0);
- if(va == ((caddr_t) - 1)) {
- DBG_ERROR(" nvram: mmap errorr");
- return 0;
- }
- DBG_INFO("nvram: va obtained=0x%x\n",(uint32)va);
- close(fd);
- return va;
-
-}
-
-static void* _nvram_mmap_free(void *va, int size)
-{
- int fd;
-
- if((fd = open(NVRAM_FILE, O_SYNC|O_RDWR, 0644)) < 0) {
- perror(" nvram: _nvram_mmap_free file open error");
- return 0;
- }
- /*flush*/
- DBG_INFO("close file with %d bytes\n",((struct nvram_header*)va)->len);
- ftruncate(fd,((struct nvram_header*)va)->len);
- msync((caddr_t)va, ((struct nvram_header*)va)->len,MS_SYNC);
- munmap((caddr_t)va, size);
- close(fd);
-}
-
-
-
-static int
-_nvram_read(void *buf)
-{
- uint32 *src, *dst;
- uint i;
- int ret=0;
-
- if (!nv_header.magic)
- return -19; /* -ENODEV */
-
- src = (uint32 *) &nv_header;
- dst = (uint32 *) buf;
-
- if(((struct nvram_header *)dst)->magic == NVRAM_MAGIC && ((struct nvram_header *)dst)->len != sizeof(struct nvram_header)){
- /* nvram exists */
- DBG_INFO("nvram exist, len=%d\n",nv_header.len);
- nv_header.len = ((struct nvram_header *)dst)->len;
- if(nv_header.config_refresh != ((struct nvram_header *)dst)->config_refresh){
- DBG_INFO("revision changed=%d\n",nv_header.config_refresh);
- ret = 0; //1; /*need merge*/
- }else{
- DBG_INFO("revision NOT changed=%d\n",nv_header.config_refresh);
- ret = 0; //2; /*no change*/
- }
- }else {
- /* nvram is empty */
- DBG_INFO("nvram empty\n");
- nv_header.len = sizeof(struct nvram_header);
- nv_header.config_refresh = 0;
- for (i = 0; i < sizeof(struct nvram_header); i += 4)
- *dst++ = *src++;
-
- /* PR2620 WAR: Read data bytes as words */
- for (; i < nv_header.len && i < NVRAM_SPACE; i += 4) {
- *dst++ = ltoh32(*src++);
- }
- ret = 0;
- }
-
- return ret;
-}
-
-static struct nvram_tuple *
-_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
-{
- if (!(t = _MALLOC_(sizeof(struct nvram_tuple) + strlen(name) + 1 + strlen(value) + 1))) {
- DBG_ERROR ( "malloc failed\n");
- return NULL;
-
- }
-
- /* Copy name */
- t->name = (char *) &t[1];
- strcpy(t->name, name);
-
- /* Copy value */
- t->value = t->name + strlen(name) + 1;
- strcpy(t->value, value);
-
- return t;
-}
-
-static void _nvram_free(struct nvram_tuple *t)
-{
- if (t) {
- _MFREE_(t, sizeof(struct nvram_tuple) + strlen(t->name) + 1 + strlen(t->value) + 1);
- }
-}
-
-/* Free all tuples. Should be locked. */
-static void
-nvram_free(void)
-{
- uint i;
- struct nvram_tuple *t, *next;
-
- DBG_INFO("nvram_free:hashtable, ");
- /* Free hash table */
- for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
- for (t = nvram_hash[i]; t; t = next) {
- next = t->next;
- _nvram_free(t);
- }
- nvram_hash[i] = NULL;
- }
-
- DBG_INFO("nvram_free: deadtable, ");
- /* Free dead table */
- for (t = nvram_dead; t; t = next) {
- next = t->next;
- _nvram_free(t);
- }
- nvram_dead = NULL;
-
- DBG_INFO("nvram_free:deletedtable, ");
-
- /* Free deleted table */
- for (t = nvram_deleted; t; t = next) {
- next = t->next;
- _nvram_free(t);
- }
- nvram_deleted = NULL;
-
-
- /* Indicate to per-port code that all tuples have been freed */
- _nvram_free(NULL);
- DBG_INFO("nvram_free(4)");
-}
-
-/* String hash */
-static INLINE uint
-hash(const char *s)
-{
- uint hash = 0;
-
- while (*s) {
- hash = 31 * hash + *s++;
- }
-
- return hash;
-}
-
-/* (Re)initialize the hash table. */
-static int
-nvram_rehash(struct nvram_header *header)
-{
- char *name, *value, *end, *eq;
-
- /* (Re)initialize hash table */
- nvram_free();
-
- /* Parse and set "name=value\0 ... \0\0" */
- name = (char *) &header[1];
- end = (char *) header + NVRAM_SPACE - 2;
- end[0] = end[1] = '\0';
- for (; *name; name = value + strlen(value) + 1) {
- if (!(eq = strchr(name, '=')))
- break;
- *eq = '\0';
- value = eq + 1;
- _nvram_set(name, value);
- *eq = '=';
- }
-
- return 0;
-}
-
-/* (Re) merge the hash table. */
-/* For conflict items, use the one in hash table, not from nvram. */
-static int
-_nvram_update(struct nvram_header *header)
-{
- char *name, *value, *end, *eq;
- struct nvram_tuple *t, *next;
- int merge=0;
-
- if( !nvram_dead && nv_header.config_refresh == header->config_refresh){
- /*nothing changed*/
- DBG_UPDATE("nothing to update revision=%d\n", nv_header.config_refresh);
- return 0;
- }
- nv_header.config_refresh = header->config_refresh; // sync revision number
-
- /* Parse and set "name=value\0 ... \0\0" */
- name = (char *) &header[1];
- end = (char *) header + NVRAM_SPACE - 2;
- end[0] = end[1] = '\0';
- for (; *name; name = value + strlen(value) + 1) {
- if (!(eq = strchr(name, '=')))
- break;
- merge=1;
- *eq = '\0';
- value= eq + 1;
- if(nvram_dead) {
- /*check if this item is in dead table, means being changed*/
- for (t=nvram_dead; t; t=next) {
- next=t->next;
- if(!strcmp(t->name,name)){
- merge = 0;
- break; /*don't merge this one*/
- }
- }
- }
-
- if(nvram_deleted) {
- /*check if this item is in deleted table, means to not use*/
- for (t=nvram_deleted; t; t=next) {
- next=t->next;
- if(!strcmp(t->name,name)){
- merge = 0;
- break; /*don't merge this one*/
- }
- }
- }
-
- if(merge) {
- if(_nvram_get(name)){
- _nvram_refresh(name, value);
- DBG_UPDATE("%s updated =%s \n",name,value);
- } else {
- _nvram_set(name, value);
- DBG_UPDATE("%s merged =%s \n",name,value);
- }
- }
- *eq = '=';
- }
- return 0;
-}
-
-/* Get the value of an NVRAM variable. */
-char *
-_nvram_get(const char *name)
-{
- uint i;
- struct nvram_tuple *t, *next;
- char *value;
-
- if (!name)
- return NULL;
-
- if(nvram_deleted) {
- /*return NULL if unset */
- for (t=nvram_deleted; t; t=next) {
- next = t->next;
- if(!strcmp(t->name, name)){
- return NULL;
- }
- }
- }
-
- /* Hash the name */
- i = hash(name) % ARRAYSIZE(nvram_hash);
-
- /* Find the associated tuple in the hash table */
- for (t = nvram_hash[i]; t && strcmp(t->name, name); t = t->next) {
- ;
- }
-
- value = t ? t->value : NULL;
-
- return value;
-}
-
-
-
-/* Refresh value of an NVRAM variable. */
-int
-_nvram_refresh(const char *name, const char *value)
-{
- uint i;
- struct nvram_tuple *t, *u, **prev;
-
- /* Hash the name */
- i = hash(name) % ARRAYSIZE(nvram_hash);
-
- /* Find the associated tuple in the hash table */
- for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev) {
- ;
- }
-
- /* (Re)allocate tuple */
- if (!(u = _nvram_realloc(t, name, value))) {
- DBG_ERROR("no memory\n");
- return -12; /* -ENOMEM */
- }
-
- /* Value reallocated */
- if (t && t == u) {
- DBG_INFO(" >> t==u set <<\n"); //why?
- return 0;
- }
-
- // release old tuple
- if (t) {
- DBG_INFO("========release %s=%s =======\n", t->name, t->value);
- *prev = t->next;
- _nvram_free(t);
- }
-
- /* Add new tuple to the hash table */
- u->next = nvram_hash[i];
- nvram_hash[i] = u;
-
- return 0;
-}
-
-
-/* Get the value of an NVRAM variable. */
-int
-_nvram_set(const char *name, const char *value)
-{
- uint i;
- struct nvram_tuple *t, *u, **prev;
-
- /* Hash the name */
- i = hash(name) % ARRAYSIZE(nvram_hash);
-
- /* Find the associated tuple in the hash table */
- for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev) {
- ;
- }
-
- /* (Re)allocate tuple */
- if (!(u = _nvram_realloc(t, name, value))) {
- DBG_ERROR("no memory\n");
- return -12; /* -ENOMEM */
- }
-
- /* Value reallocated */
- if (t && t == u) {
- DBG_INFO(" >> t==u set <<\n"); //why?
- return 0;
- }
-
- // Move old tuple to the dead table
- if (t) {
- DBG_INFO("========nvram set move (%s=%s) to dead =======\n", t->name, t->value);
- *prev = t->next;
- t->next = nvram_dead;
- nvram_dead = t;
- }
-
- /* Add new tuple to the hash table */
- u->next = nvram_hash[i];
- nvram_hash[i] = u;
-
- return 0;
-}
-
-/* Unset the value of an NVRAM variable. */
-int
-_nvram_unset(const char *name)
-{
- uint i;
- struct nvram_tuple *t, *u, **prev;
-
- if (!name)
- return 0;
-
- /* Hash the name */
- i = hash(name) % ARRAYSIZE(nvram_hash);
-
- /* Find the associated tuple in the hash table */
- for (prev = &nvram_hash[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev) {
- ;
- }
-
- /* Move it to the deleted table */
- if (t) {
- *prev = t->next;
- t->next = nvram_deleted;
- nvram_deleted = t;
- }else{
- /* create a touple and move it to deleted table*/
- if (!(u = _nvram_realloc(t, name, " "))) {
- DBG_ERROR("no memory\n");
- return -12; /* -ENOMEM */
- }
-
- u->next = nvram_deleted;
- nvram_deleted = u;
- }
-
- return 0;
-}
-
-/* Get all NVRAM variables. */
-int
-_nvram_getall(char *buf, int count)
-{
- uint i;
- struct nvram_tuple *t;
- int len = 0;
-
- bzero(buf, count);
-
- /* Write name=value\0 ... \0\0 */
- for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
- for (t = nvram_hash[i]; t; t = t->next) {
- if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
- len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
- else
- break;
- }
- }
-
- return 0;
-}
-
-/* Regenerate NVRAM. */
-int
-_nvram_commit(struct nvram_header *header)
-{
- char *ptr, *end;
- int i;
- struct nvram_tuple *t;
-
- /* Regenerate header */
- header->magic = NVRAM_MAGIC;
-
- /* Clear data area */
- ptr = (char *) header + sizeof(struct nvram_header);
- bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
-
- /* Leave space for a double NUL at the end */
- end = (char *) header + NVRAM_SPACE - 2;
-
- /* Write out all tuples */
- for (i = 0; i < ARRAYSIZE(nvram_hash); i++) {
- for (t = nvram_hash[i]; t; t = t->next) {
- if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
- break;
- ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
- DBG_COMMIT("_nvram_commit writing %s=%s \n", t->name, t->value);
- }
- }
-
- /* End with a double NUL */
- ptr += 2;
-
- /* Set new length */
- header->len = ROUNDUP(ptr - (char *) header, 4);
-
- /* Set new revision, steal config_refresh for indication */
- header->config_refresh=(++nv_header.config_refresh);
- DBG_COMMIT("new revision=%d\n",header->config_refresh);
- /* Reinitialize hash table */
- i=nvram_rehash(header);
-
- return i;
-
-}
-
-/* Initialize hash table. */
-int
-_nvram_init(void)
-{
- struct nvram_header *header;
- int ret;
-
- if (!(header = (struct nvram_header *) _NVRAM_MALLOC_(NVRAM_SPACE))) {
- DBG_ERROR("nvram_init: out of memory\n");
-
- return -12; /* -ENOMEM */
- }
-
-
- if ((ret = _nvram_read(header)) == 0 &&
- header->magic == NVRAM_MAGIC){
- /*empty*/
- nvram_rehash(header);
- }
-
-#if 0
- } else if (ret == 1 &&
- header->magic == NVRAM_MAGIC){
- /*revision made by others*/
- nvram_merge(header);
- } else if (ret == 2 &&
- header->magic == NVRAM_MAGIC && nvram_dead){
- /*internal made by self*/
- nvram_merge(header);
- } else if (ret == 2 &&
- header->magic == NVRAM_MAGIC && nvram_dead==NULL){
- /*no internal change, no external change*/
- nvram_rehash(header);
- }
-#endif
- _NVRAM_MFREE_(header, NVRAM_SPACE);
-
-
- nvram_inited=1;
- return ret;
-}
-
-/* Free hash table. */
-void
-_nvram_exit(void)
-{
- nvram_free();
-}
-
-int
-nvram_commit(void)
-{
- struct nvram_header *header;
- int ret;
- uint32 *src, *dst;
- uint i;
-
- DBG_COMMIT("==>nvram_commit\n");
-
- if(!_nvram_lock())
- goto fail_commit;
-
- if(!nvram_inited){
- _nvram_init();
- }
-
- if (!(header = (struct nvram_header *) _NVRAM_MALLOC_(NVRAM_SPACE))) {
- DBG_ERROR("nvram_commit: out of memory\n");
- ret= -12; /* -ENOMEM */
- goto fail_commit;
- }
-
- _nvram_update(header);
-
-
- /* Regenerate NVRAM */
- ret = _nvram_commit(header);
- if (ret)
- goto done_commit;
-
- src = (uint32 *) &header[1];
- dst = src;
-
- /* PR2620 WAR: Write data bytes as words */
- for (i = sizeof(struct nvram_header); i < header->len && i < NVRAM_SPACE; i += 4)
- *dst++ = htol32(*src++);
-
- done_commit:
- _NVRAM_MFREE_(header, NVRAM_SPACE);
- fail_commit:
- _nvram_unlock();
-
- DBG_COMMIT("<==nvram_commit\n");
-
- return ret;
-}
-
-char *
-nvram_get(const char *name)
-{
- char *ret=NULL;
- struct nvram_header *header;
-
- DBG_GET("==>nvram_get\n");
-
- if(!_nvram_lock())
- goto fail_get;
-
- if(!nvram_inited){
- _nvram_init();
-
- } else {
-
- if (!(header = (struct nvram_header *) _NVRAM_MALLOC_(NVRAM_SPACE))) {
- DBG_ERROR("nvram_commit: out of memory\n");
- goto fail_get;
- }
-
- _nvram_update(header);
-
- _NVRAM_MFREE_(header, NVRAM_SPACE);
-
- }
-
- ret=_nvram_get(name);
-
- _nvram_unlock();
-
- DBG_GET("%s=%s\n",name, ret);
- DBG_GET("<==nvram_get\n");
-
- return ret;
- fail_get:
- return (char*)NULL;
-}
-
-int
-nvram_set(const char *name, const char *value)
-{
- int ret=0;
- DBG_SET("==>nvram_set\n");
- if(!_nvram_lock())
- goto fail_set;
-
- if(!nvram_inited){
- _nvram_init();
- }
- DBG_SET("name=%s = %s\n",name, value);
- ret=_nvram_set(name,value);//_nvram_set_and_mark(name,value);
- _nvram_unlock();
-
- DBG_SET("<==nvram_set\n");
- return ret;
-fail_set:
- return -1;
-
-}
-
-int
-nvram_getall(char *buf, int count)
-{
- int ret;
- DBG_GETALL("==>nvram_getall\n");
- if(!_nvram_lock())
- goto fail_getall;
-
- if(!nvram_inited){
- _nvram_init();
- }
- ret=_nvram_getall(buf, count);
-
- _nvram_unlock();
-
- DBG_GETALL("<==nvram_getall\n");
- return ret;
-
-fail_getall:
- return -1;
-}
-
-int
-nvram_unset(const char *name)
-{
- int ret;
-
- DBG_UNSET("==>nvram_unset\n");
- if(!_nvram_lock())
- goto fail_unset;
-
- if(!nvram_inited){
- _nvram_init();
- }
-
- ret=_nvram_unset(name);
- _nvram_unlock();
-
- DBG_UNSET("<==nvram_unset\n");
- return ret;
-fail_unset:
- return -1;
-}
\ No newline at end of file