Commit e387efbd6535724051364fd78469ef611165e489

Authored by Oliver Metz
Committed by Tom Rini
1 parent 23ef62d741
Exists in master and in 56 other branches 8qm-imx_v2020.04_5.4.70_2.3.0, emb_lf-6.6.52-2.2.0, emb_lf_v2022.04, emb_lf_v2023.04, emb_lf_v2024.04, imx_v2015.04_4.1.15_1.0.0_ga, pitx_8mp_lf_v2020.04, smarc-8m-android-10.0.0_2.6.0, smarc-8m-android-11.0.0_2.0.0, smarc-8mp-android-11.0.0_2.0.0, smarc-emmc-imx_v2014.04_3.10.53_1.1.0_ga, smarc-emmc-imx_v2014.04_3.14.28_1.0.0_ga, smarc-imx-l5.0.0_1.0.0-ga, smarc-imx6_v2018.03_4.14.98_2.0.0_ga, smarc-imx7_v2017.03_4.9.11_1.0.0_ga, smarc-imx7_v2018.03_4.14.98_2.0.0_ga, smarc-imx_v2014.04_3.14.28_1.0.0_ga, smarc-imx_v2015.04_4.1.15_1.0.0_ga, smarc-imx_v2017.03_4.9.11_1.0.0_ga, smarc-imx_v2017.03_4.9.88_2.0.0_ga, smarc-imx_v2017.03_o8.1.0_1.3.0_8m, smarc-imx_v2018.03_4.14.78_1.0.0_ga, smarc-m6.0.1_2.1.0-ga, smarc-n7.1.2_2.0.0-ga, smarc-rel_imx_4.1.15_2.0.0_ga, smarc_8m-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8m-imx_v2019.04_4.19.35_1.1.0, smarc_8m_00d0-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga, smarc_8mm-imx_v2019.04_4.19.35_1.1.0, smarc_8mm-imx_v2020.04_5.4.24_2.1.0, smarc_8mp_lf_v2020.04, smarc_8mq-imx_v2020.04_5.4.24_2.1.0, smarc_8mq_lf_v2020.04, ti-u-boot-2015.07, v2013.10, v2013.10-smarct33, v2013.10-smartmen, v2014.01, v2014.04, v2014.04-smarct33, v2014.04-smarct33-emmc, v2014.04-smartmen, v2014.07, v2014.07-smarct33, v2014.07-smartmen, v2015.07-smarct33, v2015.07-smarct33-emmc, v2015.07-smarct4x, v2016.05-dlt, v2016.05-smarct3x, v2016.05-smarct3x-emmc, v2016.05-smarct4x, v2017.01-smarct3x, v2017.01-smarct3x-emmc, v2017.01-smarct4x

fw_env: fix writing environment for mtd devices

Signed-off-by: Oliver Metz <oliver@freetz.org>
Tested-by: Luka Perkov <luka@openwrt.org>

Showing 1 changed file with 42 additions and 28 deletions Inline Diff

1 /* 1 /*
2 * (C) Copyright 2000-2010 2 * (C) Copyright 2000-2010
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 * 4 *
5 * (C) Copyright 2008 5 * (C) Copyright 2008
6 * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de. 6 * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de.
7 * 7 *
8 * SPDX-License-Identifier: GPL-2.0+ 8 * SPDX-License-Identifier: GPL-2.0+
9 */ 9 */
10 10
11 #include <errno.h> 11 #include <errno.h>
12 #include <env_flags.h> 12 #include <env_flags.h>
13 #include <fcntl.h> 13 #include <fcntl.h>
14 #include <linux/stringify.h> 14 #include <linux/stringify.h>
15 #include <stdio.h> 15 #include <stdio.h>
16 #include <stdlib.h> 16 #include <stdlib.h>
17 #include <stddef.h> 17 #include <stddef.h>
18 #include <string.h> 18 #include <string.h>
19 #include <sys/types.h> 19 #include <sys/types.h>
20 #include <sys/ioctl.h> 20 #include <sys/ioctl.h>
21 #include <sys/stat.h> 21 #include <sys/stat.h>
22 #include <unistd.h> 22 #include <unistd.h>
23 23
24 #ifdef MTD_OLD 24 #ifdef MTD_OLD
25 # include <stdint.h> 25 # include <stdint.h>
26 # include <linux/mtd/mtd.h> 26 # include <linux/mtd/mtd.h>
27 #else 27 #else
28 # define __user /* nothing */ 28 # define __user /* nothing */
29 # include <mtd/mtd-user.h> 29 # include <mtd/mtd-user.h>
30 #endif 30 #endif
31 31
32 #include "fw_env.h" 32 #include "fw_env.h"
33 33
34 #define WHITESPACE(c) ((c == '\t') || (c == ' ')) 34 #define WHITESPACE(c) ((c == '\t') || (c == ' '))
35 35
36 #define min(x, y) ({ \ 36 #define min(x, y) ({ \
37 typeof(x) _min1 = (x); \ 37 typeof(x) _min1 = (x); \
38 typeof(y) _min2 = (y); \ 38 typeof(y) _min2 = (y); \
39 (void) (&_min1 == &_min2); \ 39 (void) (&_min1 == &_min2); \
40 _min1 < _min2 ? _min1 : _min2; }) 40 _min1 < _min2 ? _min1 : _min2; })
41 41
42 struct envdev_s { 42 struct envdev_s {
43 char devname[16]; /* Device name */ 43 char devname[16]; /* Device name */
44 ulong devoff; /* Device offset */ 44 ulong devoff; /* Device offset */
45 ulong env_size; /* environment size */ 45 ulong env_size; /* environment size */
46 ulong erase_size; /* device erase size */ 46 ulong erase_size; /* device erase size */
47 ulong env_sectors; /* number of environment sectors */ 47 ulong env_sectors; /* number of environment sectors */
48 uint8_t mtd_type; /* type of the MTD device */ 48 uint8_t mtd_type; /* type of the MTD device */
49 }; 49 };
50 50
51 static struct envdev_s envdevices[2] = 51 static struct envdev_s envdevices[2] =
52 { 52 {
53 { 53 {
54 .mtd_type = MTD_ABSENT, 54 .mtd_type = MTD_ABSENT,
55 }, { 55 }, {
56 .mtd_type = MTD_ABSENT, 56 .mtd_type = MTD_ABSENT,
57 }, 57 },
58 }; 58 };
59 static int dev_current; 59 static int dev_current;
60 60
61 #define DEVNAME(i) envdevices[(i)].devname 61 #define DEVNAME(i) envdevices[(i)].devname
62 #define DEVOFFSET(i) envdevices[(i)].devoff 62 #define DEVOFFSET(i) envdevices[(i)].devoff
63 #define ENVSIZE(i) envdevices[(i)].env_size 63 #define ENVSIZE(i) envdevices[(i)].env_size
64 #define DEVESIZE(i) envdevices[(i)].erase_size 64 #define DEVESIZE(i) envdevices[(i)].erase_size
65 #define ENVSECTORS(i) envdevices[(i)].env_sectors 65 #define ENVSECTORS(i) envdevices[(i)].env_sectors
66 #define DEVTYPE(i) envdevices[(i)].mtd_type 66 #define DEVTYPE(i) envdevices[(i)].mtd_type
67 67
68 #define CUR_ENVSIZE ENVSIZE(dev_current) 68 #define CUR_ENVSIZE ENVSIZE(dev_current)
69 69
70 #define ENV_SIZE getenvsize() 70 #define ENV_SIZE getenvsize()
71 71
72 struct env_image_single { 72 struct env_image_single {
73 uint32_t crc; /* CRC32 over data bytes */ 73 uint32_t crc; /* CRC32 over data bytes */
74 char data[]; 74 char data[];
75 }; 75 };
76 76
77 struct env_image_redundant { 77 struct env_image_redundant {
78 uint32_t crc; /* CRC32 over data bytes */ 78 uint32_t crc; /* CRC32 over data bytes */
79 unsigned char flags; /* active or obsolete */ 79 unsigned char flags; /* active or obsolete */
80 char data[]; 80 char data[];
81 }; 81 };
82 82
83 enum flag_scheme { 83 enum flag_scheme {
84 FLAG_NONE, 84 FLAG_NONE,
85 FLAG_BOOLEAN, 85 FLAG_BOOLEAN,
86 FLAG_INCREMENTAL, 86 FLAG_INCREMENTAL,
87 }; 87 };
88 88
89 struct environment { 89 struct environment {
90 void *image; 90 void *image;
91 uint32_t *crc; 91 uint32_t *crc;
92 unsigned char *flags; 92 unsigned char *flags;
93 char *data; 93 char *data;
94 enum flag_scheme flag_scheme; 94 enum flag_scheme flag_scheme;
95 }; 95 };
96 96
97 static struct environment environment = { 97 static struct environment environment = {
98 .flag_scheme = FLAG_NONE, 98 .flag_scheme = FLAG_NONE,
99 }; 99 };
100 100
101 static int HaveRedundEnv = 0; 101 static int HaveRedundEnv = 0;
102 102
103 static unsigned char active_flag = 1; 103 static unsigned char active_flag = 1;
104 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ 104 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
105 static unsigned char obsolete_flag = 0; 105 static unsigned char obsolete_flag = 0;
106 106
107 #define DEFAULT_ENV_INSTANCE_STATIC 107 #define DEFAULT_ENV_INSTANCE_STATIC
108 #include <env_default.h> 108 #include <env_default.h>
109 109
110 static int flash_io (int mode); 110 static int flash_io (int mode);
111 static char *envmatch (char * s1, char * s2); 111 static char *envmatch (char * s1, char * s2);
112 static int parse_config (void); 112 static int parse_config (void);
113 113
114 #if defined(CONFIG_FILE) 114 #if defined(CONFIG_FILE)
115 static int get_config (char *); 115 static int get_config (char *);
116 #endif 116 #endif
117 static inline ulong getenvsize (void) 117 static inline ulong getenvsize (void)
118 { 118 {
119 ulong rc = CUR_ENVSIZE - sizeof(long); 119 ulong rc = CUR_ENVSIZE - sizeof(long);
120 120
121 if (HaveRedundEnv) 121 if (HaveRedundEnv)
122 rc -= sizeof (char); 122 rc -= sizeof (char);
123 return rc; 123 return rc;
124 } 124 }
125 125
126 static char *fw_string_blank(char *s, int noblank) 126 static char *fw_string_blank(char *s, int noblank)
127 { 127 {
128 int i; 128 int i;
129 int len = strlen(s); 129 int len = strlen(s);
130 130
131 for (i = 0; i < len; i++, s++) { 131 for (i = 0; i < len; i++, s++) {
132 if ((noblank && !WHITESPACE(*s)) || 132 if ((noblank && !WHITESPACE(*s)) ||
133 (!noblank && WHITESPACE(*s))) 133 (!noblank && WHITESPACE(*s)))
134 break; 134 break;
135 } 135 }
136 if (i == len) 136 if (i == len)
137 return NULL; 137 return NULL;
138 138
139 return s; 139 return s;
140 } 140 }
141 141
142 /* 142 /*
143 * Search the environment for a variable. 143 * Search the environment for a variable.
144 * Return the value, if found, or NULL, if not found. 144 * Return the value, if found, or NULL, if not found.
145 */ 145 */
146 char *fw_getenv (char *name) 146 char *fw_getenv (char *name)
147 { 147 {
148 char *env, *nxt; 148 char *env, *nxt;
149 149
150 for (env = environment.data; *env; env = nxt + 1) { 150 for (env = environment.data; *env; env = nxt + 1) {
151 char *val; 151 char *val;
152 152
153 for (nxt = env; *nxt; ++nxt) { 153 for (nxt = env; *nxt; ++nxt) {
154 if (nxt >= &environment.data[ENV_SIZE]) { 154 if (nxt >= &environment.data[ENV_SIZE]) {
155 fprintf (stderr, "## Error: " 155 fprintf (stderr, "## Error: "
156 "environment not terminated\n"); 156 "environment not terminated\n");
157 return NULL; 157 return NULL;
158 } 158 }
159 } 159 }
160 val = envmatch (name, env); 160 val = envmatch (name, env);
161 if (!val) 161 if (!val)
162 continue; 162 continue;
163 return val; 163 return val;
164 } 164 }
165 return NULL; 165 return NULL;
166 } 166 }
167 167
168 /* 168 /*
169 * Search the default environment for a variable. 169 * Search the default environment for a variable.
170 * Return the value, if found, or NULL, if not found. 170 * Return the value, if found, or NULL, if not found.
171 */ 171 */
172 char *fw_getdefenv(char *name) 172 char *fw_getdefenv(char *name)
173 { 173 {
174 char *env, *nxt; 174 char *env, *nxt;
175 175
176 for (env = default_environment; *env; env = nxt + 1) { 176 for (env = default_environment; *env; env = nxt + 1) {
177 char *val; 177 char *val;
178 178
179 for (nxt = env; *nxt; ++nxt) { 179 for (nxt = env; *nxt; ++nxt) {
180 if (nxt >= &default_environment[ENV_SIZE]) { 180 if (nxt >= &default_environment[ENV_SIZE]) {
181 fprintf(stderr, "## Error: " 181 fprintf(stderr, "## Error: "
182 "default environment not terminated\n"); 182 "default environment not terminated\n");
183 return NULL; 183 return NULL;
184 } 184 }
185 } 185 }
186 val = envmatch(name, env); 186 val = envmatch(name, env);
187 if (!val) 187 if (!val)
188 continue; 188 continue;
189 return val; 189 return val;
190 } 190 }
191 return NULL; 191 return NULL;
192 } 192 }
193 193
194 /* 194 /*
195 * Print the current definition of one, or more, or all 195 * Print the current definition of one, or more, or all
196 * environment variables 196 * environment variables
197 */ 197 */
198 int fw_printenv (int argc, char *argv[]) 198 int fw_printenv (int argc, char *argv[])
199 { 199 {
200 char *env, *nxt; 200 char *env, *nxt;
201 int i, n_flag; 201 int i, n_flag;
202 int rc = 0; 202 int rc = 0;
203 203
204 if (fw_env_open()) 204 if (fw_env_open())
205 return -1; 205 return -1;
206 206
207 if (argc == 1) { /* Print all env variables */ 207 if (argc == 1) { /* Print all env variables */
208 for (env = environment.data; *env; env = nxt + 1) { 208 for (env = environment.data; *env; env = nxt + 1) {
209 for (nxt = env; *nxt; ++nxt) { 209 for (nxt = env; *nxt; ++nxt) {
210 if (nxt >= &environment.data[ENV_SIZE]) { 210 if (nxt >= &environment.data[ENV_SIZE]) {
211 fprintf (stderr, "## Error: " 211 fprintf (stderr, "## Error: "
212 "environment not terminated\n"); 212 "environment not terminated\n");
213 return -1; 213 return -1;
214 } 214 }
215 } 215 }
216 216
217 printf ("%s\n", env); 217 printf ("%s\n", env);
218 } 218 }
219 return 0; 219 return 0;
220 } 220 }
221 221
222 if (strcmp (argv[1], "-n") == 0) { 222 if (strcmp (argv[1], "-n") == 0) {
223 n_flag = 1; 223 n_flag = 1;
224 ++argv; 224 ++argv;
225 --argc; 225 --argc;
226 if (argc != 2) { 226 if (argc != 2) {
227 fprintf (stderr, "## Error: " 227 fprintf (stderr, "## Error: "
228 "`-n' option requires exactly one argument\n"); 228 "`-n' option requires exactly one argument\n");
229 return -1; 229 return -1;
230 } 230 }
231 } else { 231 } else {
232 n_flag = 0; 232 n_flag = 0;
233 } 233 }
234 234
235 for (i = 1; i < argc; ++i) { /* print single env variables */ 235 for (i = 1; i < argc; ++i) { /* print single env variables */
236 char *name = argv[i]; 236 char *name = argv[i];
237 char *val = NULL; 237 char *val = NULL;
238 238
239 for (env = environment.data; *env; env = nxt + 1) { 239 for (env = environment.data; *env; env = nxt + 1) {
240 240
241 for (nxt = env; *nxt; ++nxt) { 241 for (nxt = env; *nxt; ++nxt) {
242 if (nxt >= &environment.data[ENV_SIZE]) { 242 if (nxt >= &environment.data[ENV_SIZE]) {
243 fprintf (stderr, "## Error: " 243 fprintf (stderr, "## Error: "
244 "environment not terminated\n"); 244 "environment not terminated\n");
245 return -1; 245 return -1;
246 } 246 }
247 } 247 }
248 val = envmatch (name, env); 248 val = envmatch (name, env);
249 if (val) { 249 if (val) {
250 if (!n_flag) { 250 if (!n_flag) {
251 fputs (name, stdout); 251 fputs (name, stdout);
252 putc ('=', stdout); 252 putc ('=', stdout);
253 } 253 }
254 puts (val); 254 puts (val);
255 break; 255 break;
256 } 256 }
257 } 257 }
258 if (!val) { 258 if (!val) {
259 fprintf (stderr, "## Error: \"%s\" not defined\n", name); 259 fprintf (stderr, "## Error: \"%s\" not defined\n", name);
260 rc = -1; 260 rc = -1;
261 } 261 }
262 } 262 }
263 263
264 return rc; 264 return rc;
265 } 265 }
266 266
267 int fw_env_close(void) 267 int fw_env_close(void)
268 { 268 {
269 /* 269 /*
270 * Update CRC 270 * Update CRC
271 */ 271 */
272 *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE); 272 *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
273 273
274 /* write environment back to flash */ 274 /* write environment back to flash */
275 if (flash_io(O_RDWR)) { 275 if (flash_io(O_RDWR)) {
276 fprintf(stderr, 276 fprintf(stderr,
277 "Error: can't write fw_env to flash\n"); 277 "Error: can't write fw_env to flash\n");
278 return -1; 278 return -1;
279 } 279 }
280 280
281 return 0; 281 return 0;
282 } 282 }
283 283
284 284
285 /* 285 /*
286 * Set/Clear a single variable in the environment. 286 * Set/Clear a single variable in the environment.
287 * This is called in sequence to update the environment 287 * This is called in sequence to update the environment
288 * in RAM without updating the copy in flash after each set 288 * in RAM without updating the copy in flash after each set
289 */ 289 */
290 int fw_env_write(char *name, char *value) 290 int fw_env_write(char *name, char *value)
291 { 291 {
292 int len; 292 int len;
293 char *env, *nxt; 293 char *env, *nxt;
294 char *oldval = NULL; 294 char *oldval = NULL;
295 int deleting, creating, overwriting; 295 int deleting, creating, overwriting;
296 296
297 /* 297 /*
298 * search if variable with this name already exists 298 * search if variable with this name already exists
299 */ 299 */
300 for (nxt = env = environment.data; *env; env = nxt + 1) { 300 for (nxt = env = environment.data; *env; env = nxt + 1) {
301 for (nxt = env; *nxt; ++nxt) { 301 for (nxt = env; *nxt; ++nxt) {
302 if (nxt >= &environment.data[ENV_SIZE]) { 302 if (nxt >= &environment.data[ENV_SIZE]) {
303 fprintf(stderr, "## Error: " 303 fprintf(stderr, "## Error: "
304 "environment not terminated\n"); 304 "environment not terminated\n");
305 errno = EINVAL; 305 errno = EINVAL;
306 return -1; 306 return -1;
307 } 307 }
308 } 308 }
309 if ((oldval = envmatch (name, env)) != NULL) 309 if ((oldval = envmatch (name, env)) != NULL)
310 break; 310 break;
311 } 311 }
312 312
313 deleting = (oldval && !(value && strlen(value))); 313 deleting = (oldval && !(value && strlen(value)));
314 creating = (!oldval && (value && strlen(value))); 314 creating = (!oldval && (value && strlen(value)));
315 overwriting = (oldval && (value && strlen(value))); 315 overwriting = (oldval && (value && strlen(value)));
316 316
317 /* check for permission */ 317 /* check for permission */
318 if (deleting) { 318 if (deleting) {
319 if (env_flags_validate_varaccess(name, 319 if (env_flags_validate_varaccess(name,
320 ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { 320 ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
321 printf("Can't delete \"%s\"\n", name); 321 printf("Can't delete \"%s\"\n", name);
322 errno = EROFS; 322 errno = EROFS;
323 return -1; 323 return -1;
324 } 324 }
325 } else if (overwriting) { 325 } else if (overwriting) {
326 if (env_flags_validate_varaccess(name, 326 if (env_flags_validate_varaccess(name,
327 ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { 327 ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
328 printf("Can't overwrite \"%s\"\n", name); 328 printf("Can't overwrite \"%s\"\n", name);
329 errno = EROFS; 329 errno = EROFS;
330 return -1; 330 return -1;
331 } else if (env_flags_validate_varaccess(name, 331 } else if (env_flags_validate_varaccess(name,
332 ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { 332 ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
333 const char *defval = fw_getdefenv(name); 333 const char *defval = fw_getdefenv(name);
334 334
335 if (defval == NULL) 335 if (defval == NULL)
336 defval = ""; 336 defval = "";
337 if (strcmp(oldval, defval) 337 if (strcmp(oldval, defval)
338 != 0) { 338 != 0) {
339 printf("Can't overwrite \"%s\"\n", name); 339 printf("Can't overwrite \"%s\"\n", name);
340 errno = EROFS; 340 errno = EROFS;
341 return -1; 341 return -1;
342 } 342 }
343 } 343 }
344 } else if (creating) { 344 } else if (creating) {
345 if (env_flags_validate_varaccess(name, 345 if (env_flags_validate_varaccess(name,
346 ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { 346 ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
347 printf("Can't create \"%s\"\n", name); 347 printf("Can't create \"%s\"\n", name);
348 errno = EROFS; 348 errno = EROFS;
349 return -1; 349 return -1;
350 } 350 }
351 } else 351 } else
352 /* Nothing to do */ 352 /* Nothing to do */
353 return 0; 353 return 0;
354 354
355 if (deleting || overwriting) { 355 if (deleting || overwriting) {
356 if (*++nxt == '\0') { 356 if (*++nxt == '\0') {
357 *env = '\0'; 357 *env = '\0';
358 } else { 358 } else {
359 for (;;) { 359 for (;;) {
360 *env = *nxt++; 360 *env = *nxt++;
361 if ((*env == '\0') && (*nxt == '\0')) 361 if ((*env == '\0') && (*nxt == '\0'))
362 break; 362 break;
363 ++env; 363 ++env;
364 } 364 }
365 } 365 }
366 *++env = '\0'; 366 *++env = '\0';
367 } 367 }
368 368
369 /* Delete only ? */ 369 /* Delete only ? */
370 if (!value || !strlen(value)) 370 if (!value || !strlen(value))
371 return 0; 371 return 0;
372 372
373 /* 373 /*
374 * Append new definition at the end 374 * Append new definition at the end
375 */ 375 */
376 for (env = environment.data; *env || *(env + 1); ++env); 376 for (env = environment.data; *env || *(env + 1); ++env);
377 if (env > environment.data) 377 if (env > environment.data)
378 ++env; 378 ++env;
379 /* 379 /*
380 * Overflow when: 380 * Overflow when:
381 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) 381 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment)
382 */ 382 */
383 len = strlen (name) + 2; 383 len = strlen (name) + 2;
384 /* add '=' for first arg, ' ' for all others */ 384 /* add '=' for first arg, ' ' for all others */
385 len += strlen(value) + 1; 385 len += strlen(value) + 1;
386 386
387 if (len > (&environment.data[ENV_SIZE] - env)) { 387 if (len > (&environment.data[ENV_SIZE] - env)) {
388 fprintf (stderr, 388 fprintf (stderr,
389 "Error: environment overflow, \"%s\" deleted\n", 389 "Error: environment overflow, \"%s\" deleted\n",
390 name); 390 name);
391 return -1; 391 return -1;
392 } 392 }
393 393
394 while ((*env = *name++) != '\0') 394 while ((*env = *name++) != '\0')
395 env++; 395 env++;
396 *env = '='; 396 *env = '=';
397 while ((*++env = *value++) != '\0') 397 while ((*++env = *value++) != '\0')
398 ; 398 ;
399 399
400 /* end is marked with double '\0' */ 400 /* end is marked with double '\0' */
401 *++env = '\0'; 401 *++env = '\0';
402 402
403 return 0; 403 return 0;
404 } 404 }
405 405
406 /* 406 /*
407 * Deletes or sets environment variables. Returns -1 and sets errno error codes: 407 * Deletes or sets environment variables. Returns -1 and sets errno error codes:
408 * 0 - OK 408 * 0 - OK
409 * EINVAL - need at least 1 argument 409 * EINVAL - need at least 1 argument
410 * EROFS - certain variables ("ethaddr", "serial#") cannot be 410 * EROFS - certain variables ("ethaddr", "serial#") cannot be
411 * modified or deleted 411 * modified or deleted
412 * 412 *
413 */ 413 */
414 int fw_setenv(int argc, char *argv[]) 414 int fw_setenv(int argc, char *argv[])
415 { 415 {
416 int i; 416 int i;
417 size_t len; 417 size_t len;
418 char *name; 418 char *name;
419 char *value = NULL; 419 char *value = NULL;
420 420
421 if (argc < 2) { 421 if (argc < 2) {
422 errno = EINVAL; 422 errno = EINVAL;
423 return -1; 423 return -1;
424 } 424 }
425 425
426 if (fw_env_open()) { 426 if (fw_env_open()) {
427 fprintf(stderr, "Error: environment not initialized\n"); 427 fprintf(stderr, "Error: environment not initialized\n");
428 return -1; 428 return -1;
429 } 429 }
430 430
431 name = argv[1]; 431 name = argv[1];
432 432
433 if (env_flags_validate_env_set_params(argc, argv) < 0) 433 if (env_flags_validate_env_set_params(argc, argv) < 0)
434 return 1; 434 return 1;
435 435
436 len = 0; 436 len = 0;
437 for (i = 2; i < argc; ++i) { 437 for (i = 2; i < argc; ++i) {
438 char *val = argv[i]; 438 char *val = argv[i];
439 size_t val_len = strlen(val); 439 size_t val_len = strlen(val);
440 440
441 if (value) 441 if (value)
442 value[len - 1] = ' '; 442 value[len - 1] = ' ';
443 value = realloc(value, len + val_len + 1); 443 value = realloc(value, len + val_len + 1);
444 if (!value) { 444 if (!value) {
445 fprintf(stderr, 445 fprintf(stderr,
446 "Cannot malloc %zu bytes: %s\n", 446 "Cannot malloc %zu bytes: %s\n",
447 len, strerror(errno)); 447 len, strerror(errno));
448 return -1; 448 return -1;
449 } 449 }
450 450
451 memcpy(value + len, val, val_len); 451 memcpy(value + len, val, val_len);
452 len += val_len; 452 len += val_len;
453 value[len++] = '\0'; 453 value[len++] = '\0';
454 } 454 }
455 455
456 fw_env_write(name, value); 456 fw_env_write(name, value);
457 457
458 free(value); 458 free(value);
459 459
460 return fw_env_close(); 460 return fw_env_close();
461 } 461 }
462 462
463 /* 463 /*
464 * Parse a file and configure the u-boot variables. 464 * Parse a file and configure the u-boot variables.
465 * The script file has a very simple format, as follows: 465 * The script file has a very simple format, as follows:
466 * 466 *
467 * Each line has a couple with name, value: 467 * Each line has a couple with name, value:
468 * <white spaces>variable_name<white spaces>variable_value 468 * <white spaces>variable_name<white spaces>variable_value
469 * 469 *
470 * Both variable_name and variable_value are interpreted as strings. 470 * Both variable_name and variable_value are interpreted as strings.
471 * Any character after <white spaces> and before ending \r\n is interpreted 471 * Any character after <white spaces> and before ending \r\n is interpreted
472 * as variable's value (no comment allowed on these lines !) 472 * as variable's value (no comment allowed on these lines !)
473 * 473 *
474 * Comments are allowed if the first character in the line is # 474 * Comments are allowed if the first character in the line is #
475 * 475 *
476 * Returns -1 and sets errno error codes: 476 * Returns -1 and sets errno error codes:
477 * 0 - OK 477 * 0 - OK
478 * -1 - Error 478 * -1 - Error
479 */ 479 */
480 int fw_parse_script(char *fname) 480 int fw_parse_script(char *fname)
481 { 481 {
482 FILE *fp; 482 FILE *fp;
483 char dump[1024]; /* Maximum line length in the file */ 483 char dump[1024]; /* Maximum line length in the file */
484 char *name; 484 char *name;
485 char *val; 485 char *val;
486 int lineno = 0; 486 int lineno = 0;
487 int len; 487 int len;
488 int ret = 0; 488 int ret = 0;
489 489
490 if (fw_env_open()) { 490 if (fw_env_open()) {
491 fprintf(stderr, "Error: environment not initialized\n"); 491 fprintf(stderr, "Error: environment not initialized\n");
492 return -1; 492 return -1;
493 } 493 }
494 494
495 if (strcmp(fname, "-") == 0) 495 if (strcmp(fname, "-") == 0)
496 fp = stdin; 496 fp = stdin;
497 else { 497 else {
498 fp = fopen(fname, "r"); 498 fp = fopen(fname, "r");
499 if (fp == NULL) { 499 if (fp == NULL) {
500 fprintf(stderr, "I cannot open %s for reading\n", 500 fprintf(stderr, "I cannot open %s for reading\n",
501 fname); 501 fname);
502 return -1; 502 return -1;
503 } 503 }
504 } 504 }
505 505
506 while (fgets(dump, sizeof(dump), fp)) { 506 while (fgets(dump, sizeof(dump), fp)) {
507 lineno++; 507 lineno++;
508 len = strlen(dump); 508 len = strlen(dump);
509 509
510 /* 510 /*
511 * Read a whole line from the file. If the line is too long 511 * Read a whole line from the file. If the line is too long
512 * or is not terminated, reports an error and exit. 512 * or is not terminated, reports an error and exit.
513 */ 513 */
514 if (dump[len - 1] != '\n') { 514 if (dump[len - 1] != '\n') {
515 fprintf(stderr, 515 fprintf(stderr,
516 "Line %d not corrected terminated or too long\n", 516 "Line %d not corrected terminated or too long\n",
517 lineno); 517 lineno);
518 ret = -1; 518 ret = -1;
519 break; 519 break;
520 } 520 }
521 521
522 /* Drop ending line feed / carriage return */ 522 /* Drop ending line feed / carriage return */
523 while (len > 0 && (dump[len - 1] == '\n' || 523 while (len > 0 && (dump[len - 1] == '\n' ||
524 dump[len - 1] == '\r')) { 524 dump[len - 1] == '\r')) {
525 dump[len - 1] = '\0'; 525 dump[len - 1] = '\0';
526 len--; 526 len--;
527 } 527 }
528 528
529 /* Skip comment or empty lines */ 529 /* Skip comment or empty lines */
530 if ((len == 0) || dump[0] == '#') 530 if ((len == 0) || dump[0] == '#')
531 continue; 531 continue;
532 532
533 /* 533 /*
534 * Search for variable's name, 534 * Search for variable's name,
535 * remove leading whitespaces 535 * remove leading whitespaces
536 */ 536 */
537 name = fw_string_blank(dump, 1); 537 name = fw_string_blank(dump, 1);
538 if (!name) 538 if (!name)
539 continue; 539 continue;
540 540
541 /* The first white space is the end of variable name */ 541 /* The first white space is the end of variable name */
542 val = fw_string_blank(name, 0); 542 val = fw_string_blank(name, 0);
543 len = strlen(name); 543 len = strlen(name);
544 if (val) { 544 if (val) {
545 *val++ = '\0'; 545 *val++ = '\0';
546 if ((val - name) < len) 546 if ((val - name) < len)
547 val = fw_string_blank(val, 1); 547 val = fw_string_blank(val, 1);
548 else 548 else
549 val = NULL; 549 val = NULL;
550 } 550 }
551 551
552 #ifdef DEBUG 552 #ifdef DEBUG
553 fprintf(stderr, "Setting %s : %s\n", 553 fprintf(stderr, "Setting %s : %s\n",
554 name, val ? val : " removed"); 554 name, val ? val : " removed");
555 #endif 555 #endif
556 556
557 if (env_flags_validate_type(name, val) < 0) { 557 if (env_flags_validate_type(name, val) < 0) {
558 ret = -1; 558 ret = -1;
559 break; 559 break;
560 } 560 }
561 561
562 /* 562 /*
563 * If there is an error setting a variable, 563 * If there is an error setting a variable,
564 * try to save the environment and returns an error 564 * try to save the environment and returns an error
565 */ 565 */
566 if (fw_env_write(name, val)) { 566 if (fw_env_write(name, val)) {
567 fprintf(stderr, 567 fprintf(stderr,
568 "fw_env_write returns with error : %s\n", 568 "fw_env_write returns with error : %s\n",
569 strerror(errno)); 569 strerror(errno));
570 ret = -1; 570 ret = -1;
571 break; 571 break;
572 } 572 }
573 573
574 } 574 }
575 575
576 /* Close file if not stdin */ 576 /* Close file if not stdin */
577 if (strcmp(fname, "-") != 0) 577 if (strcmp(fname, "-") != 0)
578 fclose(fp); 578 fclose(fp);
579 579
580 ret |= fw_env_close(); 580 ret |= fw_env_close();
581 581
582 return ret; 582 return ret;
583 583
584 } 584 }
585 585
586 /* 586 /*
587 * Test for bad block on NAND, just returns 0 on NOR, on NAND: 587 * Test for bad block on NAND, just returns 0 on NOR, on NAND:
588 * 0 - block is good 588 * 0 - block is good
589 * > 0 - block is bad 589 * > 0 - block is bad
590 * < 0 - failed to test 590 * < 0 - failed to test
591 */ 591 */
592 static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart) 592 static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart)
593 { 593 {
594 if (mtd_type == MTD_NANDFLASH) { 594 if (mtd_type == MTD_NANDFLASH) {
595 int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); 595 int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart);
596 596
597 if (badblock < 0) { 597 if (badblock < 0) {
598 perror ("Cannot read bad block mark"); 598 perror ("Cannot read bad block mark");
599 return badblock; 599 return badblock;
600 } 600 }
601 601
602 if (badblock) { 602 if (badblock) {
603 #ifdef DEBUG 603 #ifdef DEBUG
604 fprintf (stderr, "Bad block at 0x%llx, " 604 fprintf (stderr, "Bad block at 0x%llx, "
605 "skipping\n", *blockstart); 605 "skipping\n", *blockstart);
606 #endif 606 #endif
607 return badblock; 607 return badblock;
608 } 608 }
609 } 609 }
610 610
611 return 0; 611 return 0;
612 } 612 }
613 613
614 /* 614 /*
615 * Read data from flash at an offset into a provided buffer. On NAND it skips 615 * Read data from flash at an offset into a provided buffer. On NAND it skips
616 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from 616 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
617 * the DEVOFFSET (dev) block. On NOR the loop is only run once. 617 * the DEVOFFSET (dev) block. On NOR the loop is only run once.
618 */ 618 */
619 static int flash_read_buf (int dev, int fd, void *buf, size_t count, 619 static int flash_read_buf (int dev, int fd, void *buf, size_t count,
620 off_t offset, uint8_t mtd_type) 620 off_t offset, uint8_t mtd_type)
621 { 621 {
622 size_t blocklen; /* erase / write length - one block on NAND, 622 size_t blocklen; /* erase / write length - one block on NAND,
623 0 on NOR */ 623 0 on NOR */
624 size_t processed = 0; /* progress counter */ 624 size_t processed = 0; /* progress counter */
625 size_t readlen = count; /* current read length */ 625 size_t readlen = count; /* current read length */
626 off_t top_of_range; /* end of the last block we may use */ 626 off_t top_of_range; /* end of the last block we may use */
627 off_t block_seek; /* offset inside the current block to the start 627 off_t block_seek; /* offset inside the current block to the start
628 of the data */ 628 of the data */
629 loff_t blockstart; /* running start of the current block - 629 loff_t blockstart; /* running start of the current block -
630 MEMGETBADBLOCK needs 64 bits */ 630 MEMGETBADBLOCK needs 64 bits */
631 int rc; 631 int rc;
632 632
633 blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev); 633 blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev);
634 634
635 /* Offset inside a block */ 635 /* Offset inside a block */
636 block_seek = offset - blockstart; 636 block_seek = offset - blockstart;
637 637
638 if (mtd_type == MTD_NANDFLASH) { 638 if (mtd_type == MTD_NANDFLASH) {
639 /* 639 /*
640 * NAND: calculate which blocks we are reading. We have 640 * NAND: calculate which blocks we are reading. We have
641 * to read one block at a time to skip bad blocks. 641 * to read one block at a time to skip bad blocks.
642 */ 642 */
643 blocklen = DEVESIZE (dev); 643 blocklen = DEVESIZE (dev);
644 644
645 /* 645 /*
646 * To calculate the top of the range, we have to use the 646 * To calculate the top of the range, we have to use the
647 * global DEVOFFSET (dev), which can be different from offset 647 * global DEVOFFSET (dev), which can be different from offset
648 */ 648 */
649 top_of_range = ((DEVOFFSET(dev) / blocklen) + 649 top_of_range = ((DEVOFFSET(dev) / blocklen) +
650 ENVSECTORS (dev)) * blocklen; 650 ENVSECTORS (dev)) * blocklen;
651 651
652 /* Limit to one block for the first read */ 652 /* Limit to one block for the first read */
653 if (readlen > blocklen - block_seek) 653 if (readlen > blocklen - block_seek)
654 readlen = blocklen - block_seek; 654 readlen = blocklen - block_seek;
655 } else { 655 } else {
656 blocklen = 0; 656 blocklen = 0;
657 top_of_range = offset + count; 657 top_of_range = offset + count;
658 } 658 }
659 659
660 /* This only runs once on NOR flash */ 660 /* This only runs once on NOR flash */
661 while (processed < count) { 661 while (processed < count) {
662 rc = flash_bad_block (fd, mtd_type, &blockstart); 662 rc = flash_bad_block (fd, mtd_type, &blockstart);
663 if (rc < 0) /* block test failed */ 663 if (rc < 0) /* block test failed */
664 return -1; 664 return -1;
665 665
666 if (blockstart + block_seek + readlen > top_of_range) { 666 if (blockstart + block_seek + readlen > top_of_range) {
667 /* End of range is reached */ 667 /* End of range is reached */
668 fprintf (stderr, 668 fprintf (stderr,
669 "Too few good blocks within range\n"); 669 "Too few good blocks within range\n");
670 return -1; 670 return -1;
671 } 671 }
672 672
673 if (rc) { /* block is bad */ 673 if (rc) { /* block is bad */
674 blockstart += blocklen; 674 blockstart += blocklen;
675 continue; 675 continue;
676 } 676 }
677 677
678 /* 678 /*
679 * If a block is bad, we retry in the next block at the same 679 * If a block is bad, we retry in the next block at the same
680 * offset - see common/env_nand.c::writeenv() 680 * offset - see common/env_nand.c::writeenv()
681 */ 681 */
682 lseek (fd, blockstart + block_seek, SEEK_SET); 682 lseek (fd, blockstart + block_seek, SEEK_SET);
683 683
684 rc = read (fd, buf + processed, readlen); 684 rc = read (fd, buf + processed, readlen);
685 if (rc != readlen) { 685 if (rc != readlen) {
686 fprintf (stderr, "Read error on %s: %s\n", 686 fprintf (stderr, "Read error on %s: %s\n",
687 DEVNAME (dev), strerror (errno)); 687 DEVNAME (dev), strerror (errno));
688 return -1; 688 return -1;
689 } 689 }
690 #ifdef DEBUG 690 #ifdef DEBUG
691 fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", 691 fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
692 rc, blockstart + block_seek, DEVNAME(dev)); 692 rc, blockstart + block_seek, DEVNAME(dev));
693 #endif 693 #endif
694 processed += readlen; 694 processed += readlen;
695 readlen = min (blocklen, count - processed); 695 readlen = min (blocklen, count - processed);
696 block_seek = 0; 696 block_seek = 0;
697 blockstart += blocklen; 697 blockstart += blocklen;
698 } 698 }
699 699
700 return processed; 700 return processed;
701 } 701 }
702 702
703 /* 703 /*
704 * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of 704 * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of
705 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we 705 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
706 * erase and write the whole data at once. 706 * erase and write the whole data at once.
707 */ 707 */
708 static int flash_write_buf (int dev, int fd, void *buf, size_t count, 708 static int flash_write_buf (int dev, int fd, void *buf, size_t count,
709 off_t offset, uint8_t mtd_type) 709 off_t offset, uint8_t mtd_type)
710 { 710 {
711 void *data; 711 void *data;
712 struct erase_info_user erase; 712 struct erase_info_user erase;
713 size_t blocklen; /* length of NAND block / NOR erase sector */ 713 size_t blocklen; /* length of NAND block / NOR erase sector */
714 size_t erase_len; /* whole area that can be erased - may include 714 size_t erase_len; /* whole area that can be erased - may include
715 bad blocks */ 715 bad blocks */
716 size_t erasesize; /* erase / write length - one block on NAND, 716 size_t erasesize; /* erase / write length - one block on NAND,
717 whole area on NOR */ 717 whole area on NOR */
718 size_t processed = 0; /* progress counter */ 718 size_t processed = 0; /* progress counter */
719 size_t write_total; /* total size to actually write - excluding 719 size_t write_total; /* total size to actually write - excluding
720 bad blocks */ 720 bad blocks */
721 off_t erase_offset; /* offset to the first erase block (aligned) 721 off_t erase_offset; /* offset to the first erase block (aligned)
722 below offset */ 722 below offset */
723 off_t block_seek; /* offset inside the erase block to the start 723 off_t block_seek; /* offset inside the erase block to the start
724 of the data */ 724 of the data */
725 off_t top_of_range; /* end of the last block we may use */ 725 off_t top_of_range; /* end of the last block we may use */
726 loff_t blockstart; /* running start of the current block - 726 loff_t blockstart; /* running start of the current block -
727 MEMGETBADBLOCK needs 64 bits */ 727 MEMGETBADBLOCK needs 64 bits */
728 int rc; 728 int rc;
729 729
730 blocklen = DEVESIZE (dev); 730 /*
731 * For mtd devices only offset and size of the environment do matter
732 */
733 if (mtd_type == MTD_ABSENT) {
734 blocklen = count;
735 top_of_range = offset + count;
736 erase_len = blocklen;
737 blockstart = offset;
738 block_seek = 0;
739 write_total = blocklen;
740 } else {
741 blocklen = DEVESIZE(dev);
731 742
732 top_of_range = ((DEVOFFSET(dev) / blocklen) + 743 top_of_range = ((DEVOFFSET(dev) / blocklen) +
733 ENVSECTORS (dev)) * blocklen; 744 ENVSECTORS(dev)) * blocklen;
734 745
735 erase_offset = (offset / blocklen) * blocklen; 746 erase_offset = (offset / blocklen) * blocklen;
736 747
737 /* Maximum area we may use */ 748 /* Maximum area we may use */
738 erase_len = top_of_range - erase_offset; 749 erase_len = top_of_range - erase_offset;
739 750
740 blockstart = erase_offset; 751 blockstart = erase_offset;
741 /* Offset inside a block */ 752 /* Offset inside a block */
742 block_seek = offset - erase_offset; 753 block_seek = offset - erase_offset;
743 754
744 /* 755 /*
745 * Data size we actually have to write: from the start of the block 756 * Data size we actually write: from the start of the block
746 * to the start of the data, then count bytes of data, and to the 757 * to the start of the data, then count bytes of data, and
747 * end of the block 758 * to the end of the block
748 */ 759 */
749 write_total = ((block_seek + count + blocklen - 1) / 760 write_total = ((block_seek + count + blocklen - 1) /
750 blocklen) * blocklen; 761 blocklen) * blocklen;
762 }
751 763
752 /* 764 /*
753 * Support data anywhere within erase sectors: read out the complete 765 * Support data anywhere within erase sectors: read out the complete
754 * area to be erased, replace the environment image, write the whole 766 * area to be erased, replace the environment image, write the whole
755 * block back again. 767 * block back again.
756 */ 768 */
757 if (write_total > count) { 769 if (write_total > count) {
758 data = malloc (erase_len); 770 data = malloc (erase_len);
759 if (!data) { 771 if (!data) {
760 fprintf (stderr, 772 fprintf (stderr,
761 "Cannot malloc %zu bytes: %s\n", 773 "Cannot malloc %zu bytes: %s\n",
762 erase_len, strerror (errno)); 774 erase_len, strerror (errno));
763 return -1; 775 return -1;
764 } 776 }
765 777
766 rc = flash_read_buf (dev, fd, data, write_total, erase_offset, 778 rc = flash_read_buf (dev, fd, data, write_total, erase_offset,
767 mtd_type); 779 mtd_type);
768 if (write_total != rc) 780 if (write_total != rc)
769 return -1; 781 return -1;
770 782
771 #ifdef DEBUG 783 #ifdef DEBUG
772 fprintf(stderr, "Preserving data "); 784 fprintf(stderr, "Preserving data ");
773 if (block_seek != 0) 785 if (block_seek != 0)
774 fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1); 786 fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1);
775 if (block_seek + count != write_total) { 787 if (block_seek + count != write_total) {
776 if (block_seek != 0) 788 if (block_seek != 0)
777 fprintf(stderr, " and "); 789 fprintf(stderr, " and ");
778 fprintf(stderr, "0x%lx - 0x%x", 790 fprintf(stderr, "0x%lx - 0x%x",
779 block_seek + count, write_total - 1); 791 block_seek + count, write_total - 1);
780 } 792 }
781 fprintf(stderr, "\n"); 793 fprintf(stderr, "\n");
782 #endif 794 #endif
783 /* Overwrite the old environment */ 795 /* Overwrite the old environment */
784 memcpy (data + block_seek, buf, count); 796 memcpy (data + block_seek, buf, count);
785 } else { 797 } else {
786 /* 798 /*
787 * We get here, iff offset is block-aligned and count is a 799 * We get here, iff offset is block-aligned and count is a
788 * multiple of blocklen - see write_total calculation above 800 * multiple of blocklen - see write_total calculation above
789 */ 801 */
790 data = buf; 802 data = buf;
791 } 803 }
792 804
793 if (mtd_type == MTD_NANDFLASH) { 805 if (mtd_type == MTD_NANDFLASH) {
794 /* 806 /*
795 * NAND: calculate which blocks we are writing. We have 807 * NAND: calculate which blocks we are writing. We have
796 * to write one block at a time to skip bad blocks. 808 * to write one block at a time to skip bad blocks.
797 */ 809 */
798 erasesize = blocklen; 810 erasesize = blocklen;
799 } else { 811 } else {
800 erasesize = erase_len; 812 erasesize = erase_len;
801 } 813 }
802 814
803 erase.length = erasesize; 815 erase.length = erasesize;
804 816
805 /* This only runs once on NOR flash and SPI-dataflash */ 817 /* This only runs once on NOR flash and SPI-dataflash */
806 while (processed < write_total) { 818 while (processed < write_total) {
807 rc = flash_bad_block (fd, mtd_type, &blockstart); 819 rc = flash_bad_block (fd, mtd_type, &blockstart);
808 if (rc < 0) /* block test failed */ 820 if (rc < 0) /* block test failed */
809 return rc; 821 return rc;
810 822
811 if (blockstart + erasesize > top_of_range) { 823 if (blockstart + erasesize > top_of_range) {
812 fprintf (stderr, "End of range reached, aborting\n"); 824 fprintf (stderr, "End of range reached, aborting\n");
813 return -1; 825 return -1;
814 } 826 }
815 827
816 if (rc) { /* block is bad */ 828 if (rc) { /* block is bad */
817 blockstart += blocklen; 829 blockstart += blocklen;
818 continue; 830 continue;
819 } 831 }
820 832
821 erase.start = blockstart; 833 if (mtd_type != MTD_ABSENT) {
822 ioctl (fd, MEMUNLOCK, &erase); 834 erase.start = blockstart;
823 /* These do not need an explicit erase cycle */ 835 ioctl(fd, MEMUNLOCK, &erase);
824 if (mtd_type != MTD_ABSENT && 836 /* These do not need an explicit erase cycle */
825 mtd_type != MTD_DATAFLASH) 837 if (mtd_type != MTD_DATAFLASH)
826 if (ioctl (fd, MEMERASE, &erase) != 0) { 838 if (ioctl(fd, MEMERASE, &erase) != 0) {
827 fprintf (stderr, "MTD erase error on %s: %s\n", 839 fprintf(stderr,
828 DEVNAME (dev), 840 "MTD erase error on %s: %s\n",
829 strerror (errno)); 841 DEVNAME(dev), strerror(errno));
830 return -1; 842 return -1;
831 } 843 }
844 }
832 845
833 if (lseek (fd, blockstart, SEEK_SET) == -1) { 846 if (lseek (fd, blockstart, SEEK_SET) == -1) {
834 fprintf (stderr, 847 fprintf (stderr,
835 "Seek error on %s: %s\n", 848 "Seek error on %s: %s\n",
836 DEVNAME (dev), strerror (errno)); 849 DEVNAME (dev), strerror (errno));
837 return -1; 850 return -1;
838 } 851 }
839 852
840 #ifdef DEBUG 853 #ifdef DEBUG
841 fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize, 854 fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize,
842 blockstart); 855 blockstart);
843 #endif 856 #endif
844 if (write (fd, data + processed, erasesize) != erasesize) { 857 if (write (fd, data + processed, erasesize) != erasesize) {
845 fprintf (stderr, "Write error on %s: %s\n", 858 fprintf (stderr, "Write error on %s: %s\n",
846 DEVNAME (dev), strerror (errno)); 859 DEVNAME (dev), strerror (errno));
847 return -1; 860 return -1;
848 } 861 }
849 862
850 ioctl (fd, MEMLOCK, &erase); 863 if (mtd_type != MTD_ABSENT)
864 ioctl(fd, MEMLOCK, &erase);
851 865
852 processed += blocklen; 866 processed += blocklen;
853 block_seek = 0; 867 block_seek = 0;
854 blockstart += blocklen; 868 blockstart += blocklen;
855 } 869 }
856 870
857 if (write_total > count) 871 if (write_total > count)
858 free (data); 872 free (data);
859 873
860 return processed; 874 return processed;
861 } 875 }
862 876
863 /* 877 /*
864 * Set obsolete flag at offset - NOR flash only 878 * Set obsolete flag at offset - NOR flash only
865 */ 879 */
866 static int flash_flag_obsolete (int dev, int fd, off_t offset) 880 static int flash_flag_obsolete (int dev, int fd, off_t offset)
867 { 881 {
868 int rc; 882 int rc;
869 struct erase_info_user erase; 883 struct erase_info_user erase;
870 884
871 erase.start = DEVOFFSET (dev); 885 erase.start = DEVOFFSET (dev);
872 erase.length = DEVESIZE (dev); 886 erase.length = DEVESIZE (dev);
873 /* This relies on the fact, that obsolete_flag == 0 */ 887 /* This relies on the fact, that obsolete_flag == 0 */
874 rc = lseek (fd, offset, SEEK_SET); 888 rc = lseek (fd, offset, SEEK_SET);
875 if (rc < 0) { 889 if (rc < 0) {
876 fprintf (stderr, "Cannot seek to set the flag on %s \n", 890 fprintf (stderr, "Cannot seek to set the flag on %s \n",
877 DEVNAME (dev)); 891 DEVNAME (dev));
878 return rc; 892 return rc;
879 } 893 }
880 ioctl (fd, MEMUNLOCK, &erase); 894 ioctl (fd, MEMUNLOCK, &erase);
881 rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); 895 rc = write (fd, &obsolete_flag, sizeof (obsolete_flag));
882 ioctl (fd, MEMLOCK, &erase); 896 ioctl (fd, MEMLOCK, &erase);
883 if (rc < 0) 897 if (rc < 0)
884 perror ("Could not set obsolete flag"); 898 perror ("Could not set obsolete flag");
885 899
886 return rc; 900 return rc;
887 } 901 }
888 902
889 static int flash_write (int fd_current, int fd_target, int dev_target) 903 static int flash_write (int fd_current, int fd_target, int dev_target)
890 { 904 {
891 int rc; 905 int rc;
892 906
893 switch (environment.flag_scheme) { 907 switch (environment.flag_scheme) {
894 case FLAG_NONE: 908 case FLAG_NONE:
895 break; 909 break;
896 case FLAG_INCREMENTAL: 910 case FLAG_INCREMENTAL:
897 (*environment.flags)++; 911 (*environment.flags)++;
898 break; 912 break;
899 case FLAG_BOOLEAN: 913 case FLAG_BOOLEAN:
900 *environment.flags = active_flag; 914 *environment.flags = active_flag;
901 break; 915 break;
902 default: 916 default:
903 fprintf (stderr, "Unimplemented flash scheme %u \n", 917 fprintf (stderr, "Unimplemented flash scheme %u \n",
904 environment.flag_scheme); 918 environment.flag_scheme);
905 return -1; 919 return -1;
906 } 920 }
907 921
908 #ifdef DEBUG 922 #ifdef DEBUG
909 fprintf(stderr, "Writing new environment at 0x%lx on %s\n", 923 fprintf(stderr, "Writing new environment at 0x%lx on %s\n",
910 DEVOFFSET (dev_target), DEVNAME (dev_target)); 924 DEVOFFSET (dev_target), DEVNAME (dev_target));
911 #endif 925 #endif
912 rc = flash_write_buf(dev_target, fd_target, environment.image, 926 rc = flash_write_buf(dev_target, fd_target, environment.image,
913 CUR_ENVSIZE, DEVOFFSET(dev_target), 927 CUR_ENVSIZE, DEVOFFSET(dev_target),
914 DEVTYPE(dev_target)); 928 DEVTYPE(dev_target));
915 if (rc < 0) 929 if (rc < 0)
916 return rc; 930 return rc;
917 931
918 if (environment.flag_scheme == FLAG_BOOLEAN) { 932 if (environment.flag_scheme == FLAG_BOOLEAN) {
919 /* Have to set obsolete flag */ 933 /* Have to set obsolete flag */
920 off_t offset = DEVOFFSET (dev_current) + 934 off_t offset = DEVOFFSET (dev_current) +
921 offsetof (struct env_image_redundant, flags); 935 offsetof (struct env_image_redundant, flags);
922 #ifdef DEBUG 936 #ifdef DEBUG
923 fprintf(stderr, 937 fprintf(stderr,
924 "Setting obsolete flag in environment at 0x%lx on %s\n", 938 "Setting obsolete flag in environment at 0x%lx on %s\n",
925 DEVOFFSET (dev_current), DEVNAME (dev_current)); 939 DEVOFFSET (dev_current), DEVNAME (dev_current));
926 #endif 940 #endif
927 flash_flag_obsolete (dev_current, fd_current, offset); 941 flash_flag_obsolete (dev_current, fd_current, offset);
928 } 942 }
929 943
930 return 0; 944 return 0;
931 } 945 }
932 946
933 static int flash_read (int fd) 947 static int flash_read (int fd)
934 { 948 {
935 struct mtd_info_user mtdinfo; 949 struct mtd_info_user mtdinfo;
936 struct stat st; 950 struct stat st;
937 int rc; 951 int rc;
938 952
939 rc = fstat(fd, &st); 953 rc = fstat(fd, &st);
940 if (rc < 0) { 954 if (rc < 0) {
941 fprintf(stderr, "Cannot stat the file %s\n", 955 fprintf(stderr, "Cannot stat the file %s\n",
942 DEVNAME(dev_current)); 956 DEVNAME(dev_current));
943 return -1; 957 return -1;
944 } 958 }
945 959
946 if (S_ISCHR(st.st_mode)) { 960 if (S_ISCHR(st.st_mode)) {
947 rc = ioctl(fd, MEMGETINFO, &mtdinfo); 961 rc = ioctl(fd, MEMGETINFO, &mtdinfo);
948 if (rc < 0) { 962 if (rc < 0) {
949 fprintf(stderr, "Cannot get MTD information for %s\n", 963 fprintf(stderr, "Cannot get MTD information for %s\n",
950 DEVNAME(dev_current)); 964 DEVNAME(dev_current));
951 return -1; 965 return -1;
952 } 966 }
953 if (mtdinfo.type != MTD_NORFLASH && 967 if (mtdinfo.type != MTD_NORFLASH &&
954 mtdinfo.type != MTD_NANDFLASH && 968 mtdinfo.type != MTD_NANDFLASH &&
955 mtdinfo.type != MTD_DATAFLASH && 969 mtdinfo.type != MTD_DATAFLASH &&
956 mtdinfo.type != MTD_UBIVOLUME) { 970 mtdinfo.type != MTD_UBIVOLUME) {
957 fprintf (stderr, "Unsupported flash type %u on %s\n", 971 fprintf (stderr, "Unsupported flash type %u on %s\n",
958 mtdinfo.type, DEVNAME(dev_current)); 972 mtdinfo.type, DEVNAME(dev_current));
959 return -1; 973 return -1;
960 } 974 }
961 } else { 975 } else {
962 memset(&mtdinfo, 0, sizeof(mtdinfo)); 976 memset(&mtdinfo, 0, sizeof(mtdinfo));
963 mtdinfo.type = MTD_ABSENT; 977 mtdinfo.type = MTD_ABSENT;
964 } 978 }
965 979
966 DEVTYPE(dev_current) = mtdinfo.type; 980 DEVTYPE(dev_current) = mtdinfo.type;
967 981
968 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, 982 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
969 DEVOFFSET (dev_current), mtdinfo.type); 983 DEVOFFSET (dev_current), mtdinfo.type);
970 984
971 return (rc != CUR_ENVSIZE) ? -1 : 0; 985 return (rc != CUR_ENVSIZE) ? -1 : 0;
972 } 986 }
973 987
974 static int flash_io (int mode) 988 static int flash_io (int mode)
975 { 989 {
976 int fd_current, fd_target, rc, dev_target; 990 int fd_current, fd_target, rc, dev_target;
977 991
978 /* dev_current: fd_current, erase_current */ 992 /* dev_current: fd_current, erase_current */
979 fd_current = open (DEVNAME (dev_current), mode); 993 fd_current = open (DEVNAME (dev_current), mode);
980 if (fd_current < 0) { 994 if (fd_current < 0) {
981 fprintf (stderr, 995 fprintf (stderr,
982 "Can't open %s: %s\n", 996 "Can't open %s: %s\n",
983 DEVNAME (dev_current), strerror (errno)); 997 DEVNAME (dev_current), strerror (errno));
984 return -1; 998 return -1;
985 } 999 }
986 1000
987 if (mode == O_RDWR) { 1001 if (mode == O_RDWR) {
988 if (HaveRedundEnv) { 1002 if (HaveRedundEnv) {
989 /* switch to next partition for writing */ 1003 /* switch to next partition for writing */
990 dev_target = !dev_current; 1004 dev_target = !dev_current;
991 /* dev_target: fd_target, erase_target */ 1005 /* dev_target: fd_target, erase_target */
992 fd_target = open (DEVNAME (dev_target), mode); 1006 fd_target = open (DEVNAME (dev_target), mode);
993 if (fd_target < 0) { 1007 if (fd_target < 0) {
994 fprintf (stderr, 1008 fprintf (stderr,
995 "Can't open %s: %s\n", 1009 "Can't open %s: %s\n",
996 DEVNAME (dev_target), 1010 DEVNAME (dev_target),
997 strerror (errno)); 1011 strerror (errno));
998 rc = -1; 1012 rc = -1;
999 goto exit; 1013 goto exit;
1000 } 1014 }
1001 } else { 1015 } else {
1002 dev_target = dev_current; 1016 dev_target = dev_current;
1003 fd_target = fd_current; 1017 fd_target = fd_current;
1004 } 1018 }
1005 1019
1006 rc = flash_write (fd_current, fd_target, dev_target); 1020 rc = flash_write (fd_current, fd_target, dev_target);
1007 1021
1008 if (HaveRedundEnv) { 1022 if (HaveRedundEnv) {
1009 if (close (fd_target)) { 1023 if (close (fd_target)) {
1010 fprintf (stderr, 1024 fprintf (stderr,
1011 "I/O error on %s: %s\n", 1025 "I/O error on %s: %s\n",
1012 DEVNAME (dev_target), 1026 DEVNAME (dev_target),
1013 strerror (errno)); 1027 strerror (errno));
1014 rc = -1; 1028 rc = -1;
1015 } 1029 }
1016 } 1030 }
1017 } else { 1031 } else {
1018 rc = flash_read (fd_current); 1032 rc = flash_read (fd_current);
1019 } 1033 }
1020 1034
1021 exit: 1035 exit:
1022 if (close (fd_current)) { 1036 if (close (fd_current)) {
1023 fprintf (stderr, 1037 fprintf (stderr,
1024 "I/O error on %s: %s\n", 1038 "I/O error on %s: %s\n",
1025 DEVNAME (dev_current), strerror (errno)); 1039 DEVNAME (dev_current), strerror (errno));
1026 return -1; 1040 return -1;
1027 } 1041 }
1028 1042
1029 return rc; 1043 return rc;
1030 } 1044 }
1031 1045
1032 /* 1046 /*
1033 * s1 is either a simple 'name', or a 'name=value' pair. 1047 * s1 is either a simple 'name', or a 'name=value' pair.
1034 * s2 is a 'name=value' pair. 1048 * s2 is a 'name=value' pair.
1035 * If the names match, return the value of s2, else NULL. 1049 * If the names match, return the value of s2, else NULL.
1036 */ 1050 */
1037 1051
1038 static char *envmatch (char * s1, char * s2) 1052 static char *envmatch (char * s1, char * s2)
1039 { 1053 {
1040 if (s1 == NULL || s2 == NULL) 1054 if (s1 == NULL || s2 == NULL)
1041 return NULL; 1055 return NULL;
1042 1056
1043 while (*s1 == *s2++) 1057 while (*s1 == *s2++)
1044 if (*s1++ == '=') 1058 if (*s1++ == '=')
1045 return s2; 1059 return s2;
1046 if (*s1 == '\0' && *(s2 - 1) == '=') 1060 if (*s1 == '\0' && *(s2 - 1) == '=')
1047 return s2; 1061 return s2;
1048 return NULL; 1062 return NULL;
1049 } 1063 }
1050 1064
1051 /* 1065 /*
1052 * Prevent confusion if running from erased flash memory 1066 * Prevent confusion if running from erased flash memory
1053 */ 1067 */
1054 int fw_env_open(void) 1068 int fw_env_open(void)
1055 { 1069 {
1056 int crc0, crc0_ok; 1070 int crc0, crc0_ok;
1057 unsigned char flag0; 1071 unsigned char flag0;
1058 void *addr0; 1072 void *addr0;
1059 1073
1060 int crc1, crc1_ok; 1074 int crc1, crc1_ok;
1061 unsigned char flag1; 1075 unsigned char flag1;
1062 void *addr1; 1076 void *addr1;
1063 1077
1064 struct env_image_single *single; 1078 struct env_image_single *single;
1065 struct env_image_redundant *redundant; 1079 struct env_image_redundant *redundant;
1066 1080
1067 if (parse_config ()) /* should fill envdevices */ 1081 if (parse_config ()) /* should fill envdevices */
1068 return -1; 1082 return -1;
1069 1083
1070 addr0 = calloc(1, CUR_ENVSIZE); 1084 addr0 = calloc(1, CUR_ENVSIZE);
1071 if (addr0 == NULL) { 1085 if (addr0 == NULL) {
1072 fprintf(stderr, 1086 fprintf(stderr,
1073 "Not enough memory for environment (%ld bytes)\n", 1087 "Not enough memory for environment (%ld bytes)\n",
1074 CUR_ENVSIZE); 1088 CUR_ENVSIZE);
1075 return -1; 1089 return -1;
1076 } 1090 }
1077 1091
1078 /* read environment from FLASH to local buffer */ 1092 /* read environment from FLASH to local buffer */
1079 environment.image = addr0; 1093 environment.image = addr0;
1080 1094
1081 if (HaveRedundEnv) { 1095 if (HaveRedundEnv) {
1082 redundant = addr0; 1096 redundant = addr0;
1083 environment.crc = &redundant->crc; 1097 environment.crc = &redundant->crc;
1084 environment.flags = &redundant->flags; 1098 environment.flags = &redundant->flags;
1085 environment.data = redundant->data; 1099 environment.data = redundant->data;
1086 } else { 1100 } else {
1087 single = addr0; 1101 single = addr0;
1088 environment.crc = &single->crc; 1102 environment.crc = &single->crc;
1089 environment.flags = NULL; 1103 environment.flags = NULL;
1090 environment.data = single->data; 1104 environment.data = single->data;
1091 } 1105 }
1092 1106
1093 dev_current = 0; 1107 dev_current = 0;
1094 if (flash_io (O_RDONLY)) 1108 if (flash_io (O_RDONLY))
1095 return -1; 1109 return -1;
1096 1110
1097 crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); 1111 crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
1098 crc0_ok = (crc0 == *environment.crc); 1112 crc0_ok = (crc0 == *environment.crc);
1099 if (!HaveRedundEnv) { 1113 if (!HaveRedundEnv) {
1100 if (!crc0_ok) { 1114 if (!crc0_ok) {
1101 fprintf (stderr, 1115 fprintf (stderr,
1102 "Warning: Bad CRC, using default environment\n"); 1116 "Warning: Bad CRC, using default environment\n");
1103 memcpy(environment.data, default_environment, sizeof default_environment); 1117 memcpy(environment.data, default_environment, sizeof default_environment);
1104 } 1118 }
1105 } else { 1119 } else {
1106 flag0 = *environment.flags; 1120 flag0 = *environment.flags;
1107 1121
1108 dev_current = 1; 1122 dev_current = 1;
1109 addr1 = calloc(1, CUR_ENVSIZE); 1123 addr1 = calloc(1, CUR_ENVSIZE);
1110 if (addr1 == NULL) { 1124 if (addr1 == NULL) {
1111 fprintf(stderr, 1125 fprintf(stderr,
1112 "Not enough memory for environment (%ld bytes)\n", 1126 "Not enough memory for environment (%ld bytes)\n",
1113 CUR_ENVSIZE); 1127 CUR_ENVSIZE);
1114 return -1; 1128 return -1;
1115 } 1129 }
1116 redundant = addr1; 1130 redundant = addr1;
1117 1131
1118 /* 1132 /*
1119 * have to set environment.image for flash_read(), careful - 1133 * have to set environment.image for flash_read(), careful -
1120 * other pointers in environment still point inside addr0 1134 * other pointers in environment still point inside addr0
1121 */ 1135 */
1122 environment.image = addr1; 1136 environment.image = addr1;
1123 if (flash_io (O_RDONLY)) 1137 if (flash_io (O_RDONLY))
1124 return -1; 1138 return -1;
1125 1139
1126 /* Check flag scheme compatibility */ 1140 /* Check flag scheme compatibility */
1127 if (DEVTYPE(dev_current) == MTD_NORFLASH && 1141 if (DEVTYPE(dev_current) == MTD_NORFLASH &&
1128 DEVTYPE(!dev_current) == MTD_NORFLASH) { 1142 DEVTYPE(!dev_current) == MTD_NORFLASH) {
1129 environment.flag_scheme = FLAG_BOOLEAN; 1143 environment.flag_scheme = FLAG_BOOLEAN;
1130 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && 1144 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
1131 DEVTYPE(!dev_current) == MTD_NANDFLASH) { 1145 DEVTYPE(!dev_current) == MTD_NANDFLASH) {
1132 environment.flag_scheme = FLAG_INCREMENTAL; 1146 environment.flag_scheme = FLAG_INCREMENTAL;
1133 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH && 1147 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
1134 DEVTYPE(!dev_current) == MTD_DATAFLASH) { 1148 DEVTYPE(!dev_current) == MTD_DATAFLASH) {
1135 environment.flag_scheme = FLAG_BOOLEAN; 1149 environment.flag_scheme = FLAG_BOOLEAN;
1136 } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME && 1150 } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
1137 DEVTYPE(!dev_current) == MTD_UBIVOLUME) { 1151 DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
1138 environment.flag_scheme = FLAG_INCREMENTAL; 1152 environment.flag_scheme = FLAG_INCREMENTAL;
1139 } else if (DEVTYPE(dev_current) == MTD_ABSENT && 1153 } else if (DEVTYPE(dev_current) == MTD_ABSENT &&
1140 DEVTYPE(!dev_current) == MTD_ABSENT) { 1154 DEVTYPE(!dev_current) == MTD_ABSENT) {
1141 environment.flag_scheme = FLAG_INCREMENTAL; 1155 environment.flag_scheme = FLAG_INCREMENTAL;
1142 } else { 1156 } else {
1143 fprintf (stderr, "Incompatible flash types!\n"); 1157 fprintf (stderr, "Incompatible flash types!\n");
1144 return -1; 1158 return -1;
1145 } 1159 }
1146 1160
1147 crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); 1161 crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
1148 crc1_ok = (crc1 == redundant->crc); 1162 crc1_ok = (crc1 == redundant->crc);
1149 flag1 = redundant->flags; 1163 flag1 = redundant->flags;
1150 1164
1151 if (crc0_ok && !crc1_ok) { 1165 if (crc0_ok && !crc1_ok) {
1152 dev_current = 0; 1166 dev_current = 0;
1153 } else if (!crc0_ok && crc1_ok) { 1167 } else if (!crc0_ok && crc1_ok) {
1154 dev_current = 1; 1168 dev_current = 1;
1155 } else if (!crc0_ok && !crc1_ok) { 1169 } else if (!crc0_ok && !crc1_ok) {
1156 fprintf (stderr, 1170 fprintf (stderr,
1157 "Warning: Bad CRC, using default environment\n"); 1171 "Warning: Bad CRC, using default environment\n");
1158 memcpy (environment.data, default_environment, 1172 memcpy (environment.data, default_environment,
1159 sizeof default_environment); 1173 sizeof default_environment);
1160 dev_current = 0; 1174 dev_current = 0;
1161 } else { 1175 } else {
1162 switch (environment.flag_scheme) { 1176 switch (environment.flag_scheme) {
1163 case FLAG_BOOLEAN: 1177 case FLAG_BOOLEAN:
1164 if (flag0 == active_flag && 1178 if (flag0 == active_flag &&
1165 flag1 == obsolete_flag) { 1179 flag1 == obsolete_flag) {
1166 dev_current = 0; 1180 dev_current = 0;
1167 } else if (flag0 == obsolete_flag && 1181 } else if (flag0 == obsolete_flag &&
1168 flag1 == active_flag) { 1182 flag1 == active_flag) {
1169 dev_current = 1; 1183 dev_current = 1;
1170 } else if (flag0 == flag1) { 1184 } else if (flag0 == flag1) {
1171 dev_current = 0; 1185 dev_current = 0;
1172 } else if (flag0 == 0xFF) { 1186 } else if (flag0 == 0xFF) {
1173 dev_current = 0; 1187 dev_current = 0;
1174 } else if (flag1 == 0xFF) { 1188 } else if (flag1 == 0xFF) {
1175 dev_current = 1; 1189 dev_current = 1;
1176 } else { 1190 } else {
1177 dev_current = 0; 1191 dev_current = 0;
1178 } 1192 }
1179 break; 1193 break;
1180 case FLAG_INCREMENTAL: 1194 case FLAG_INCREMENTAL:
1181 if (flag0 == 255 && flag1 == 0) 1195 if (flag0 == 255 && flag1 == 0)
1182 dev_current = 1; 1196 dev_current = 1;
1183 else if ((flag1 == 255 && flag0 == 0) || 1197 else if ((flag1 == 255 && flag0 == 0) ||
1184 flag0 >= flag1) 1198 flag0 >= flag1)
1185 dev_current = 0; 1199 dev_current = 0;
1186 else /* flag1 > flag0 */ 1200 else /* flag1 > flag0 */
1187 dev_current = 1; 1201 dev_current = 1;
1188 break; 1202 break;
1189 default: 1203 default:
1190 fprintf (stderr, "Unknown flag scheme %u \n", 1204 fprintf (stderr, "Unknown flag scheme %u \n",
1191 environment.flag_scheme); 1205 environment.flag_scheme);
1192 return -1; 1206 return -1;
1193 } 1207 }
1194 } 1208 }
1195 1209
1196 /* 1210 /*
1197 * If we are reading, we don't need the flag and the CRC any 1211 * If we are reading, we don't need the flag and the CRC any
1198 * more, if we are writing, we will re-calculate CRC and update 1212 * more, if we are writing, we will re-calculate CRC and update
1199 * flags before writing out 1213 * flags before writing out
1200 */ 1214 */
1201 if (dev_current) { 1215 if (dev_current) {
1202 environment.image = addr1; 1216 environment.image = addr1;
1203 environment.crc = &redundant->crc; 1217 environment.crc = &redundant->crc;
1204 environment.flags = &redundant->flags; 1218 environment.flags = &redundant->flags;
1205 environment.data = redundant->data; 1219 environment.data = redundant->data;
1206 free (addr0); 1220 free (addr0);
1207 } else { 1221 } else {
1208 environment.image = addr0; 1222 environment.image = addr0;
1209 /* Other pointers are already set */ 1223 /* Other pointers are already set */
1210 free (addr1); 1224 free (addr1);
1211 } 1225 }
1212 #ifdef DEBUG 1226 #ifdef DEBUG
1213 fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current)); 1227 fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
1214 #endif 1228 #endif
1215 } 1229 }
1216 return 0; 1230 return 0;
1217 } 1231 }
1218 1232
1219 1233
1220 static int parse_config () 1234 static int parse_config ()
1221 { 1235 {
1222 struct stat st; 1236 struct stat st;
1223 1237
1224 #if defined(CONFIG_FILE) 1238 #if defined(CONFIG_FILE)
1225 /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ 1239 /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
1226 if (get_config (CONFIG_FILE)) { 1240 if (get_config (CONFIG_FILE)) {
1227 fprintf (stderr, 1241 fprintf (stderr,
1228 "Cannot parse config file: %s\n", strerror (errno)); 1242 "Cannot parse config file: %s\n", strerror (errno));
1229 return -1; 1243 return -1;
1230 } 1244 }
1231 #else 1245 #else
1232 strcpy (DEVNAME (0), DEVICE1_NAME); 1246 strcpy (DEVNAME (0), DEVICE1_NAME);
1233 DEVOFFSET (0) = DEVICE1_OFFSET; 1247 DEVOFFSET (0) = DEVICE1_OFFSET;
1234 ENVSIZE (0) = ENV1_SIZE; 1248 ENVSIZE (0) = ENV1_SIZE;
1235 /* Default values are: erase-size=env-size, #sectors=1 */ 1249 /* Default values are: erase-size=env-size, #sectors=1 */
1236 DEVESIZE (0) = ENVSIZE (0); 1250 DEVESIZE (0) = ENVSIZE (0);
1237 ENVSECTORS (0) = 1; 1251 ENVSECTORS (0) = 1;
1238 #ifdef DEVICE1_ESIZE 1252 #ifdef DEVICE1_ESIZE
1239 DEVESIZE (0) = DEVICE1_ESIZE; 1253 DEVESIZE (0) = DEVICE1_ESIZE;
1240 #endif 1254 #endif
1241 #ifdef DEVICE1_ENVSECTORS 1255 #ifdef DEVICE1_ENVSECTORS
1242 ENVSECTORS (0) = DEVICE1_ENVSECTORS; 1256 ENVSECTORS (0) = DEVICE1_ENVSECTORS;
1243 #endif 1257 #endif
1244 1258
1245 #ifdef HAVE_REDUND 1259 #ifdef HAVE_REDUND
1246 strcpy (DEVNAME (1), DEVICE2_NAME); 1260 strcpy (DEVNAME (1), DEVICE2_NAME);
1247 DEVOFFSET (1) = DEVICE2_OFFSET; 1261 DEVOFFSET (1) = DEVICE2_OFFSET;
1248 ENVSIZE (1) = ENV2_SIZE; 1262 ENVSIZE (1) = ENV2_SIZE;
1249 /* Default values are: erase-size=env-size, #sectors=1 */ 1263 /* Default values are: erase-size=env-size, #sectors=1 */
1250 DEVESIZE (1) = ENVSIZE (1); 1264 DEVESIZE (1) = ENVSIZE (1);
1251 ENVSECTORS (1) = 1; 1265 ENVSECTORS (1) = 1;
1252 #ifdef DEVICE2_ESIZE 1266 #ifdef DEVICE2_ESIZE
1253 DEVESIZE (1) = DEVICE2_ESIZE; 1267 DEVESIZE (1) = DEVICE2_ESIZE;
1254 #endif 1268 #endif
1255 #ifdef DEVICE2_ENVSECTORS 1269 #ifdef DEVICE2_ENVSECTORS
1256 ENVSECTORS (1) = DEVICE2_ENVSECTORS; 1270 ENVSECTORS (1) = DEVICE2_ENVSECTORS;
1257 #endif 1271 #endif
1258 HaveRedundEnv = 1; 1272 HaveRedundEnv = 1;
1259 #endif 1273 #endif
1260 #endif 1274 #endif
1261 if (stat (DEVNAME (0), &st)) { 1275 if (stat (DEVNAME (0), &st)) {
1262 fprintf (stderr, 1276 fprintf (stderr,
1263 "Cannot access MTD device %s: %s\n", 1277 "Cannot access MTD device %s: %s\n",
1264 DEVNAME (0), strerror (errno)); 1278 DEVNAME (0), strerror (errno));
1265 return -1; 1279 return -1;
1266 } 1280 }
1267 1281
1268 if (HaveRedundEnv && stat (DEVNAME (1), &st)) { 1282 if (HaveRedundEnv && stat (DEVNAME (1), &st)) {
1269 fprintf (stderr, 1283 fprintf (stderr,
1270 "Cannot access MTD device %s: %s\n", 1284 "Cannot access MTD device %s: %s\n",
1271 DEVNAME (1), strerror (errno)); 1285 DEVNAME (1), strerror (errno));
1272 return -1; 1286 return -1;
1273 } 1287 }
1274 return 0; 1288 return 0;
1275 } 1289 }
1276 1290
1277 #if defined(CONFIG_FILE) 1291 #if defined(CONFIG_FILE)
1278 static int get_config (char *fname) 1292 static int get_config (char *fname)
1279 { 1293 {
1280 FILE *fp; 1294 FILE *fp;
1281 int i = 0; 1295 int i = 0;
1282 int rc; 1296 int rc;
1283 char dump[128]; 1297 char dump[128];
1284 1298
1285 fp = fopen (fname, "r"); 1299 fp = fopen (fname, "r");
1286 if (fp == NULL) 1300 if (fp == NULL)
1287 return -1; 1301 return -1;
1288 1302
1289 while (i < 2 && fgets (dump, sizeof (dump), fp)) { 1303 while (i < 2 && fgets (dump, sizeof (dump), fp)) {
1290 /* Skip incomplete conversions and comment strings */ 1304 /* Skip incomplete conversions and comment strings */
1291 if (dump[0] == '#') 1305 if (dump[0] == '#')
1292 continue; 1306 continue;
1293 1307
1294 rc = sscanf (dump, "%s %lx %lx %lx %lx", 1308 rc = sscanf (dump, "%s %lx %lx %lx %lx",
1295 DEVNAME (i), 1309 DEVNAME (i),
1296 &DEVOFFSET (i), 1310 &DEVOFFSET (i),
1297 &ENVSIZE (i), 1311 &ENVSIZE (i),
1298 &DEVESIZE (i), 1312 &DEVESIZE (i),
1299 &ENVSECTORS (i)); 1313 &ENVSECTORS (i));
1300 1314
1301 if (rc < 3) 1315 if (rc < 3)
1302 continue; 1316 continue;
1303 1317
1304 if (rc < 4) 1318 if (rc < 4)
1305 /* Assume the erase size is the same as the env-size */ 1319 /* Assume the erase size is the same as the env-size */
1306 DEVESIZE(i) = ENVSIZE(i); 1320 DEVESIZE(i) = ENVSIZE(i);
1307 1321
1308 if (rc < 5) 1322 if (rc < 5)
1309 /* Default - 1 sector */ 1323 /* Default - 1 sector */
1310 ENVSECTORS (i) = 1; 1324 ENVSECTORS (i) = 1;
1311 1325
1312 i++; 1326 i++;
1313 } 1327 }
1314 fclose (fp); 1328 fclose (fp);
1315 1329
1316 HaveRedundEnv = i - 1; 1330 HaveRedundEnv = i - 1;
1317 if (!i) { /* No valid entries found */ 1331 if (!i) { /* No valid entries found */
1318 errno = EINVAL; 1332 errno = EINVAL;
1319 return -1; 1333 return -1;
1320 } else 1334 } else
1321 return 0; 1335 return 0;
1322 } 1336 }
1323 #endif 1337 #endif
1324 1338