--- /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