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