243 lines
5.1 KiB
C
243 lines
5.1 KiB
C
/******************************************************************************
|
|
* 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 */
|
|
}
|
|
|