aboutsummaryrefslogtreecommitdiffstats
path: root/roms/SLOF/lib/libnvram/envvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/SLOF/lib/libnvram/envvar.c')
-rw-r--r--roms/SLOF/lib/libnvram/envvar.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/roms/SLOF/lib/libnvram/envvar.c b/roms/SLOF/lib/libnvram/envvar.c
new file mode 100644
index 000000000..d413e9750
--- /dev/null
+++ b/roms/SLOF/lib/libnvram/envvar.c
@@ -0,0 +1,242 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdint.h>
+#include "../libc/include/stdio.h"
+#include "../libc/include/string.h"
+#include "../libc/include/stdlib.h"
+#include "nvram.h"
+
+/* returns the offset of the first byte after the searched envvar */
+static int get_past_env_pos(partition_t part, char *envvar, int evlen)
+{
+ int offset, len;
+ static char temp[256];
+ uint8_t data;
+
+ offset=part.addr;
+
+ memset(temp, 0, 256);
+
+ do {
+ len=0;
+ while((data=nvram_read_byte(offset++)) && len < 256) {
+ temp[len++]=data;
+ }
+ if (!strncmp(envvar, temp, evlen)) {
+ return offset;
+ }
+ } while (len);
+
+ return -1;
+}
+
+/**
+ * @param partition name of the envvar partition
+ * @param envvar name of the environment variable
+ * @param evlen string length of the envvar parameter
+ * @return pointer to temporary string containing the value of envvar
+ */
+char *nvram_get_env(partition_t part, char *envvar, unsigned evlen)
+{
+ static char temp[256+1];
+ int len, offset;
+ uint8_t data;
+
+ DEBUG("nvram_get_env %p... ", envvar);
+ if(!part.addr) {
+ /* ERROR: No environment variable partition */
+ DEBUG("invalid partition.\n");
+ return NULL;
+ }
+
+ offset=part.addr;
+
+ do {
+ len=0;
+ while((data=nvram_read_byte(offset++)) && len < 256) {
+ temp[len++]=data;
+ }
+ temp[len]=0;
+
+ if (!strncmp(envvar, temp, evlen)) {
+ int pos=0;
+ while (temp[pos]!='=' && pos < len) pos++;
+ // DEBUG("value='%s'\n", temp+pos+1);
+ return temp+pos+1;
+ }
+ } while (len);
+
+ DEBUG("not found\n");
+ return NULL;
+}
+
+static int find_last_envvar(partition_t part)
+{
+ uint8_t last, current;
+ int offset;
+
+ offset=part.addr;
+
+ last=nvram_read_byte(part.addr);
+
+ for (offset=part.addr; offset<(int)(part.addr+part.len); offset++) {
+ current=nvram_read_byte(offset);
+ if(!last && !current)
+ return offset;
+
+ last=current;
+ }
+
+ return -1;
+}
+
+int nvram_add_env(partition_t part, char *envvar, unsigned evlen, char *value, unsigned vallen)
+{
+ unsigned i, freespace, last, len, offset;
+
+ /* Find offset where we can write */
+ last = find_last_envvar(part);
+
+ /* How much space do we have left? */
+ freespace = part.addr+part.len-last;
+
+ /* how long is the entry we want to write? */
+ len = evlen + vallen + 2;
+
+ if(freespace<len) {
+ // TODO try to increase partition size
+ return -1;
+ }
+
+ offset=last;
+
+ for (i = 0; i < evlen; i++)
+ nvram_write_byte(offset++, envvar[i]);
+
+ nvram_write_byte(offset++, '=');
+
+ for (i = 0; i < vallen; i++)
+ nvram_write_byte(offset++, value[i]);
+
+ return 0;
+}
+
+int nvram_del_env(partition_t part, char *envvar, unsigned evlen)
+{
+ int last, current, pos, i;
+ char *buffer;
+
+ if(!part.addr)
+ return -1;
+
+ last=find_last_envvar(part);
+ current = pos = get_past_env_pos(part, envvar, evlen);
+
+ // TODO is this really required?
+ /* go back to non-0 value */
+ current--;
+
+ while (nvram_read_byte(current))
+ current--;
+
+ // TODO is this required?
+ current++;
+
+ buffer=get_nvram_buffer(last-pos);
+
+ for (i=0; i<last-pos; i++)
+ buffer[i]=nvram_read_byte(i+pos);
+
+ for (i=0; i<last-pos; i++)
+ nvram_write_byte(i+current, buffer[i]);
+
+ free_nvram_buffer(buffer);
+
+ erase_nvram(last, current+last-pos);
+
+ return 0;
+}
+
+int nvram_set_env(partition_t part, char *envvar, unsigned evlen, char *value, unsigned vallen)
+{
+ char *oldvalue, *buffer;
+ unsigned last, current, buffersize, i;
+
+ DEBUG("nvram_set_env %lx[%lx]: %p=>%p\n", part.addr, part.len, envvar, value);
+
+ if(!part.addr)
+ return -1;
+
+ /* Check whether the environment variable exists already */
+ oldvalue = nvram_get_env(part, envvar, evlen);
+
+ if (oldvalue == NULL)
+ return nvram_add_env(part, envvar, evlen, value, vallen);
+
+
+ /* The value did not change. So we succeeded! */
+ if (strlen(oldvalue) == vallen && !strncmp(oldvalue, value, vallen))
+ return 0;
+
+ /* we need to overwrite environment variables, back them up first */
+
+ // DEBUG("overwriting existing environment variable\n");
+
+ /* allocate a buffer */
+ last=find_last_envvar(part);
+ current = get_past_env_pos(part, envvar, evlen);
+ buffersize = last - current;
+ buffer=get_nvram_buffer(buffersize);
+ if(!buffer)
+ return -1;
+
+ for (i=0; i<buffersize; i++) {
+ buffer[i] = nvram_read_byte(current+i);
+ }
+
+ /* walk back until the = */
+ while (nvram_read_byte(current)!='=') {
+ current--;
+ }
+
+ /* Start at envvar= */
+ current++;
+
+ /* Write the new value */
+ for(i = 0; i < vallen; i++) {
+ nvram_write_byte(current++, value[i]);
+ }
+
+ /* Write end of string marker */
+ nvram_write_byte(current++, 0);
+
+ /* Copy back the buffer */
+ for (i=0; i<buffersize; i++) {
+ nvram_write_byte(current++, buffer[i]);
+ }
+
+ free_nvram_buffer(buffer);
+
+ /* If the new environment variable content is shorter than the old one,
+ * we need to erase the rest of the bytes
+ */
+
+ if (current<last) {
+ for(i=current; i<last; i++) {
+ nvram_write_byte(i, 0);
+ }
+ }
+
+ return 0; /* success */
+}
+