/****************************************************************************** * 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, int 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, int evlen, char *value, int vallen) { int freespace, last, len, offset; unsigned int i; /* 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, int 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, int evlen, char *value, int vallen) { char *oldvalue, *buffer; int 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 */ }