1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12 
13 #include <stdint.h>
14 #include "../libc/include/stdio.h"
15 #include "../libc/include/string.h"
16 #include "../libc/include/stdlib.h"
17 #include "nvram.h"
18 
19 /* returns the offset of the first byte after the searched envvar */
get_past_env_pos(partition_t part,char * envvar,int evlen)20 static int get_past_env_pos(partition_t part, char *envvar, int evlen)
21 {
22 	int offset, len;
23 	static char temp[256];
24 	uint8_t data;
25 
26 	offset=part.addr;
27 
28 	memset(temp, 0, 256);
29 
30 	do {
31 		len=0;
32 		while((data=nvram_read_byte(offset++)) && len < 256) {
33 			temp[len++]=data;
34 		}
35 		if (!strncmp(envvar, temp, evlen)) {
36 			return offset;
37 		}
38 	} while (len);
39 
40 	return -1;
41 }
42 
43 /**
44  * @param partition name of the envvar partition
45  * @param envvar name of the environment variable
46  * @param evlen string length of the envvar parameter
47  * @return pointer to temporary string containing the value of envvar
48  */
nvram_get_env(partition_t part,char * envvar,int evlen)49 char *nvram_get_env(partition_t part, char *envvar, int evlen)
50 {
51 	static char temp[256+1];
52 	int len, offset;
53 	uint8_t data;
54 
55 	DEBUG("nvram_get_env %p... ", envvar);
56 	if(!part.addr) {
57 		/* ERROR: No environment variable partition */
58 		DEBUG("invalid partition.\n");
59 		return NULL;
60 	}
61 
62 	offset=part.addr;
63 
64 	do {
65 		len=0;
66 		while((data=nvram_read_byte(offset++)) && len < 256) {
67 			temp[len++]=data;
68 		}
69 		temp[len]=0;
70 
71 		if (!strncmp(envvar, temp, evlen)) {
72 			int pos=0;
73 			while (temp[pos]!='=' && pos < len) pos++;
74 			// DEBUG("value='%s'\n", temp+pos+1);
75 			return temp+pos+1;
76 		}
77 	} while (len);
78 
79 	DEBUG("not found\n");
80 	return NULL;
81 }
82 
find_last_envvar(partition_t part)83 static int find_last_envvar(partition_t part)
84 {
85 	uint8_t last, current;
86 	int offset;
87 
88 	offset=part.addr;
89 
90 	last=nvram_read_byte(part.addr);
91 
92 	for (offset=part.addr; offset<(int)(part.addr+part.len); offset++) {
93 		current=nvram_read_byte(offset);
94 		if(!last && !current)
95 			return offset;
96 
97 		last=current;
98 	}
99 
100 	return -1;
101 }
102 
nvram_add_env(partition_t part,char * envvar,int evlen,char * value,int vallen)103 int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen)
104 {
105 	int freespace, last, len, offset;
106 	unsigned int i;
107 
108 	/* Find offset where we can write */
109 	last = find_last_envvar(part);
110 
111 	/* How much space do we have left? */
112 	freespace = part.addr+part.len-last;
113 
114 	/* how long is the entry we want to write? */
115 	len = evlen + vallen + 2;
116 
117 	if(freespace<len) {
118 		// TODO try to increase partition size
119 		return -1;
120 	}
121 
122 	offset=last;
123 
124 	for (i = 0; i < evlen; i++)
125 		nvram_write_byte(offset++, envvar[i]);
126 
127 	nvram_write_byte(offset++, '=');
128 
129 	for (i = 0; i < vallen; i++)
130 		nvram_write_byte(offset++, value[i]);
131 
132 	return 0;
133 }
134 
nvram_del_env(partition_t part,char * envvar,int evlen)135 int nvram_del_env(partition_t part, char *envvar, int evlen)
136 {
137 	int last, current, pos, i;
138 	char *buffer;
139 
140 	if(!part.addr)
141 		return -1;
142 
143 	last=find_last_envvar(part);
144 	current = pos = get_past_env_pos(part, envvar, evlen);
145 
146 	// TODO is this really required?
147 	/* go back to non-0 value */
148 	current--;
149 
150 	while (nvram_read_byte(current))
151 		current--;
152 
153 	// TODO is this required?
154 	current++;
155 
156 	buffer=get_nvram_buffer(last-pos);
157 
158 	for (i=0; i<last-pos; i++)
159 		buffer[i]=nvram_read_byte(i+pos);
160 
161 	for (i=0; i<last-pos; i++)
162 		nvram_write_byte(i+current, buffer[i]);
163 
164 	free_nvram_buffer(buffer);
165 
166 	erase_nvram(last, current+last-pos);
167 
168 	return 0;
169 }
170 
nvram_set_env(partition_t part,char * envvar,int evlen,char * value,int vallen)171 int nvram_set_env(partition_t part, char *envvar, int evlen, char *value, int vallen)
172 {
173 	char *oldvalue, *buffer;
174 	int last, current, buffersize, i;
175 
176 	DEBUG("nvram_set_env %lx[%lx]: %p=>%p\n", part.addr, part.len, envvar, value);
177 
178 	if(!part.addr)
179 		return -1;
180 
181 	/* Check whether the environment variable exists already */
182 	oldvalue = nvram_get_env(part, envvar, evlen);
183 
184 	if (oldvalue == NULL)
185 		return nvram_add_env(part, envvar, evlen, value, vallen);
186 
187 
188 	/* The value did not change. So we succeeded! */
189 	if (strlen(oldvalue) == vallen && !strncmp(oldvalue, value, vallen))
190 		return 0;
191 
192 	/* we need to overwrite environment variables, back them up first */
193 
194 	// DEBUG("overwriting existing environment variable\n");
195 
196 	/* allocate a buffer */
197 	last=find_last_envvar(part);
198 	current = get_past_env_pos(part, envvar, evlen);
199 	buffersize = last - current;
200 	buffer=get_nvram_buffer(buffersize);
201 	if(!buffer)
202 		return -1;
203 
204 	for (i=0; i<buffersize; i++) {
205 		buffer[i] = nvram_read_byte(current+i);
206 	}
207 
208 	/* walk back until the = */
209 	while (nvram_read_byte(current)!='=') {
210 		current--;
211 	}
212 
213 	/* Start at envvar= */
214 	current++;
215 
216 	/* Write the new value */
217 	for(i = 0; i < vallen; i++) {
218 		nvram_write_byte(current++, value[i]);
219 	}
220 
221 	/* Write end of string marker */
222 	nvram_write_byte(current++, 0);
223 
224 	/* Copy back the buffer */
225 	for (i=0; i<buffersize; i++) {
226 		nvram_write_byte(current++, buffer[i]);
227 	}
228 
229 	free_nvram_buffer(buffer);
230 
231 	/* If the new environment variable content is shorter than the old one,
232 	 * we need to erase the rest of the bytes
233 	 */
234 
235 	if (current<last) {
236 		for(i=current; i<last; i++) {
237 			nvram_write_byte(i, 0);
238 		}
239 	}
240 
241 	return 0; /* success */
242 }
243 
244