123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- /*
- * NVRAM variable manipulation (common)
- *
- * Copyright 2004, Broadcom Corporation
- * Copyright 2009-2010, OpenWrt.org
- * All Rights Reserved.
- *
- * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
- * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
- * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
- *
- */
- #include "nvram.h"
- #define TRACE(msg) \
- printf("%s(%i) in %s(): %s\n", \
- __FILE__, __LINE__, __FUNCTION__, msg ? msg : "?")
- /* Size of "nvram" MTD partition */
- size_t nvram_part_size = 0;
- /*
- * -- Helper functions --
- */
- /* String hash */
- static uint32_t hash(const char *s)
- {
- uint32_t hash = 0;
- while (*s)
- hash = 31 * hash + *s++;
- return hash;
- }
- /* Free all tuples. */
- static void _nvram_free(nvram_handle_t *h)
- {
- uint32_t i;
- nvram_tuple_t *t, *next;
- /* Free hash table */
- for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
- for (t = h->nvram_hash[i]; t; t = next) {
- next = t->next;
- free(t);
- }
- h->nvram_hash[i] = NULL;
- }
- /* Free dead table */
- for (t = h->nvram_dead; t; t = next) {
- next = t->next;
- free(t);
- }
- h->nvram_dead = NULL;
- }
- /* (Re)allocate NVRAM tuples. */
- static nvram_tuple_t * _nvram_realloc( nvram_handle_t *h, nvram_tuple_t *t,
- const char *name, const char *value )
- {
- if ((strlen(value) + 1) > h->length - h->offset)
- return NULL;
- if (!t) {
- if (!(t = malloc(sizeof(nvram_tuple_t) + strlen(name) + 1)))
- return NULL;
- /* Copy name */
- t->name = (char *) &t[1];
- strcpy(t->name, name);
- t->value = NULL;
- }
- /* Copy value */
- if (!t->value || strcmp(t->value, value))
- {
- if(!(t->value = (char *) realloc(t->value, strlen(value)+1)))
- return NULL;
- strcpy(t->value, value);
- t->value[strlen(value)] = '\0';
- }
- return t;
- }
- /* (Re)initialize the hash table. */
- static int _nvram_rehash(nvram_handle_t *h)
- {
- nvram_header_t *header = nvram_header(h);
- char buf[] = "0xXXXXXXXX", *name, *value, *eq;
- /* (Re)initialize hash table */
- _nvram_free(h);
- /* Parse and set "name=value\0 ... \0\0" */
- name = (char *) &header[1];
- for (; *name; name = value + strlen(value) + 1) {
- if (!(eq = strchr(name, '=')))
- break;
- *eq = '\0';
- value = eq + 1;
- nvram_set(h, name, value);
- *eq = '=';
- }
- /* Set special SDRAM parameters */
- if (!nvram_get(h, "sdram_init")) {
- sprintf(buf, "0x%04X", (uint16_t)(header->crc_ver_init >> 16));
- nvram_set(h, "sdram_init", buf);
- }
- if (!nvram_get(h, "sdram_config")) {
- sprintf(buf, "0x%04X", (uint16_t)(header->config_refresh & 0xffff));
- nvram_set(h, "sdram_config", buf);
- }
- if (!nvram_get(h, "sdram_refresh")) {
- sprintf(buf, "0x%04X",
- (uint16_t)((header->config_refresh >> 16) & 0xffff));
- nvram_set(h, "sdram_refresh", buf);
- }
- if (!nvram_get(h, "sdram_ncdl")) {
- sprintf(buf, "0x%08X", header->config_ncdl);
- nvram_set(h, "sdram_ncdl", buf);
- }
- return 0;
- }
- /*
- * -- Public functions --
- */
- /* Get nvram header. */
- nvram_header_t * nvram_header(nvram_handle_t *h)
- {
- return (nvram_header_t *) &h->mmap[h->offset];
- }
- /* Get the value of an NVRAM variable. */
- char * nvram_get(nvram_handle_t *h, const char *name)
- {
- uint32_t i;
- nvram_tuple_t *t;
- char *value;
- if (!name)
- return NULL;
- /* Hash the name */
- i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
- /* Find the associated tuple in the hash table */
- for (t = h->nvram_hash[i]; t && strcmp(t->name, name); t = t->next);
- value = t ? t->value : NULL;
- return value;
- }
- /* Set the value of an NVRAM variable. */
- int nvram_set(nvram_handle_t *h, const char *name, const char *value)
- {
- uint32_t i;
- nvram_tuple_t *t, *u, **prev;
- /* Hash the name */
- i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
- /* Find the associated tuple in the hash table */
- for (prev = &h->nvram_hash[i], t = *prev;
- t && strcmp(t->name, name); prev = &t->next, t = *prev);
- /* (Re)allocate tuple */
- if (!(u = _nvram_realloc(h, t, name, value)))
- return -12; /* -ENOMEM */
- /* Value reallocated */
- if (t && t == u)
- return 0;
- /* Move old tuple to the dead table */
- if (t) {
- *prev = t->next;
- t->next = h->nvram_dead;
- h->nvram_dead = t;
- }
- /* Add new tuple to the hash table */
- u->next = h->nvram_hash[i];
- h->nvram_hash[i] = u;
- return 0;
- }
- /* Unset the value of an NVRAM variable. */
- int nvram_unset(nvram_handle_t *h, const char *name)
- {
- uint32_t i;
- nvram_tuple_t *t, **prev;
- if (!name)
- return 0;
- /* Hash the name */
- i = hash(name) % NVRAM_ARRAYSIZE(h->nvram_hash);
- /* Find the associated tuple in the hash table */
- for (prev = &h->nvram_hash[i], t = *prev;
- t && strcmp(t->name, name); prev = &t->next, t = *prev);
- /* Move it to the dead table */
- if (t) {
- *prev = t->next;
- t->next = h->nvram_dead;
- h->nvram_dead = t;
- }
- return 0;
- }
- /* Get all NVRAM variables. */
- nvram_tuple_t * nvram_getall(nvram_handle_t *h)
- {
- int i;
- nvram_tuple_t *t, *l, *x;
- l = NULL;
- for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
- for (t = h->nvram_hash[i]; t; t = t->next) {
- if( (x = (nvram_tuple_t *) malloc(sizeof(nvram_tuple_t))) != NULL )
- {
- x->name = t->name;
- x->value = t->value;
- x->next = l;
- l = x;
- }
- else
- {
- break;
- }
- }
- }
- return l;
- }
- /* Regenerate NVRAM. */
- int nvram_commit(nvram_handle_t *h)
- {
- nvram_header_t *header = nvram_header(h);
- char *init, *config, *refresh, *ncdl;
- char *ptr, *end;
- int i;
- nvram_tuple_t *t;
- nvram_header_t tmp;
- uint8_t crc;
- /* Regenerate header */
- header->magic = NVRAM_MAGIC;
- header->crc_ver_init = (NVRAM_VERSION << 8);
- if (!(init = nvram_get(h, "sdram_init")) ||
- !(config = nvram_get(h, "sdram_config")) ||
- !(refresh = nvram_get(h, "sdram_refresh")) ||
- !(ncdl = nvram_get(h, "sdram_ncdl"))) {
- header->crc_ver_init |= SDRAM_INIT << 16;
- header->config_refresh = SDRAM_CONFIG;
- header->config_refresh |= SDRAM_REFRESH << 16;
- header->config_ncdl = 0;
- } else {
- header->crc_ver_init |= (strtoul(init, NULL, 0) & 0xffff) << 16;
- header->config_refresh = strtoul(config, NULL, 0) & 0xffff;
- header->config_refresh |= (strtoul(refresh, NULL, 0) & 0xffff) << 16;
- header->config_ncdl = strtoul(ncdl, NULL, 0);
- }
- /* Clear data area */
- ptr = (char *) header + sizeof(nvram_header_t);
- memset(ptr, 0xFF, nvram_part_size - h->offset - sizeof(nvram_header_t));
- memset(&tmp, 0, sizeof(nvram_header_t));
- /* Leave space for a double NUL at the end */
- end = (char *) header + nvram_part_size - h->offset - 2;
- /* Write out all tuples */
- for (i = 0; i < NVRAM_ARRAYSIZE(h->nvram_hash); i++) {
- for (t = h->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;
- }
- }
- /* End with a double NULL and pad to 4 bytes */
- *ptr = '\0';
- ptr++;
- if( (int)ptr % 4 )
- memset(ptr, 0, 4 - ((int)ptr % 4));
- ptr++;
- /* Set new length */
- header->len = NVRAM_ROUNDUP(ptr - (char *) header, 4);
- /* Little-endian CRC8 over the last 11 bytes of the header */
- tmp.crc_ver_init = header->crc_ver_init;
- tmp.config_refresh = header->config_refresh;
- tmp.config_ncdl = header->config_ncdl;
- crc = hndcrc8((unsigned char *) &tmp + NVRAM_CRC_START_POSITION,
- sizeof(nvram_header_t) - NVRAM_CRC_START_POSITION, 0xff);
- /* Continue CRC8 over data bytes */
- crc = hndcrc8((unsigned char *) &header[0] + sizeof(nvram_header_t),
- header->len - sizeof(nvram_header_t), crc);
- /* Set new CRC8 */
- header->crc_ver_init |= crc;
- /* Write out */
- msync(h->mmap, h->length, MS_SYNC);
- fsync(h->fd);
- /* Reinitialize hash table */
- return _nvram_rehash(h);
- }
- /* Open NVRAM and obtain a handle. */
- nvram_handle_t * nvram_open(const char *file, int rdonly)
- {
- int i;
- int fd;
- char *mtd = NULL;
- nvram_handle_t *h;
- nvram_header_t *header;
- int offset = -1;
- /* If erase size or file are undefined then try to define them */
- if( (nvram_part_size == 0) || (file == NULL) )
- {
- /* Finding the mtd will set the appropriate erase size */
- if( (mtd = nvram_find_mtd()) == NULL || nvram_part_size == 0 )
- {
- free(mtd);
- return NULL;
- }
- }
- if( (fd = open(file ? file : mtd, O_RDWR)) > -1 )
- {
- char *mmap_area = (char *) mmap(
- NULL, nvram_part_size, PROT_READ | PROT_WRITE,
- (( rdonly == NVRAM_RO ) ? MAP_PRIVATE : MAP_SHARED) | MAP_LOCKED, fd, 0);
- if( mmap_area != MAP_FAILED )
- {
- /*
- * Start looking for NVRAM_MAGIC at beginning of MTD
- * partition. Stop if there is less than NVRAM_MIN_SPACE
- * to check, that was the lowest used size.
- */
- for( i = 0; i <= ((nvram_part_size - NVRAM_MIN_SPACE) / sizeof(uint32_t)); i++ )
- {
- if( ((uint32_t *)mmap_area)[i] == NVRAM_MAGIC )
- {
- offset = i * sizeof(uint32_t);
- break;
- }
- }
- if( offset < 0 )
- {
- free(mtd);
- return NULL;
- }
- else if( (h = malloc(sizeof(nvram_handle_t))) != NULL )
- {
- memset(h, 0, sizeof(nvram_handle_t));
- h->fd = fd;
- h->mmap = mmap_area;
- h->length = nvram_part_size;
- h->offset = offset;
- header = nvram_header(h);
- if (header->magic == NVRAM_MAGIC &&
- (rdonly || header->len < h->length - h->offset)) {
- _nvram_rehash(h);
- free(mtd);
- return h;
- }
- else
- {
- munmap(h->mmap, h->length);
- free(h);
- }
- }
- }
- }
- free(mtd);
- return NULL;
- }
- /* Close NVRAM and free memory. */
- int nvram_close(nvram_handle_t *h)
- {
- _nvram_free(h);
- munmap(h->mmap, h->length);
- close(h->fd);
- free(h);
- return 0;
- }
- /* Determine NVRAM device node. */
- char * nvram_find_mtd(void)
- {
- FILE *fp;
- int i, part_size;
- char dev[PATH_MAX];
- char *path = NULL;
- struct stat s;
- if ((fp = fopen("/proc/mtd", "r")))
- {
- while( fgets(dev, sizeof(dev), fp) )
- {
- if( strstr(dev, "nvram") && sscanf(dev, "mtd%d: %08x", &i, &part_size) )
- {
- nvram_part_size = part_size;
- sprintf(dev, "/dev/mtdblock%d", i);
- if( stat(dev, &s) > -1 && (s.st_mode & S_IFBLK) )
- {
- if( (path = (char *) malloc(strlen(dev)+1)) != NULL )
- {
- strncpy(path, dev, strlen(dev)+1);
- break;
- }
- }
- }
- }
- fclose(fp);
- }
- return path;
- }
- /* Check NVRAM staging file. */
- char * nvram_find_staging(void)
- {
- struct stat s;
- if( (stat(NVRAM_STAGING, &s) > -1) && (s.st_mode & S_IFREG) )
- {
- return NVRAM_STAGING;
- }
- return NULL;
- }
- /* Copy NVRAM contents to staging file. */
- int nvram_to_staging(void)
- {
- int fdmtd, fdstg, stat;
- char *mtd = nvram_find_mtd();
- char buf[nvram_part_size];
- stat = -1;
- if( (mtd != NULL) && (nvram_part_size > 0) )
- {
- if( (fdmtd = open(mtd, O_RDONLY)) > -1 )
- {
- if( read(fdmtd, buf, sizeof(buf)) == sizeof(buf) )
- {
- if((fdstg = open(NVRAM_STAGING, O_WRONLY | O_CREAT, 0600)) > -1)
- {
- write(fdstg, buf, sizeof(buf));
- fsync(fdstg);
- close(fdstg);
- stat = 0;
- }
- }
- close(fdmtd);
- }
- }
- free(mtd);
- return stat;
- }
- /* Copy staging file to NVRAM device. */
- int staging_to_nvram(void)
- {
- int fdmtd, fdstg, stat;
- char *mtd = nvram_find_mtd();
- char buf[nvram_part_size];
- stat = -1;
- if( (mtd != NULL) && (nvram_part_size > 0) )
- {
- if( (fdstg = open(NVRAM_STAGING, O_RDONLY)) > -1 )
- {
- if( read(fdstg, buf, sizeof(buf)) == sizeof(buf) )
- {
- if( (fdmtd = open(mtd, O_WRONLY | O_SYNC)) > -1 )
- {
- write(fdmtd, buf, sizeof(buf));
- fsync(fdmtd);
- close(fdmtd);
- stat = 0;
- }
- }
- close(fdstg);
- if( !stat )
- stat = unlink(NVRAM_STAGING) ? 1 : 0;
- }
- }
- free(mtd);
- return stat;
- }
|