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