]>
Commit | Line | Data |
---|---|---|
6aff3115 | 1 | /* |
4a6fd34b | 2 | * (C) Copyright 2000-2003 |
6aff3115 WD |
3 | * Wolfgang Denk, DENX Software Engineering, [email protected]. |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
4a6fd34b | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
6aff3115 WD |
16 | * GNU General Public License for more details. |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | #include <errno.h> | |
25 | #include <fcntl.h> | |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <stddef.h> | |
29 | #include <string.h> | |
30 | #include <sys/types.h> | |
31 | #include <sys/ioctl.h> | |
32 | #include <sys/stat.h> | |
33 | #include <unistd.h> | |
34 | #include <linux/mtd/mtd.h> | |
35 | #include "fw_env.h" | |
36 | ||
4a6fd34b | 37 | typedef unsigned char uchar; |
6aff3115 WD |
38 | |
39 | #define CMD_GETENV "fw_printenv" | |
40 | #define CMD_SETENV "fw_setenv" | |
41 | ||
42 | typedef struct envdev_s { | |
4a6fd34b WD |
43 | uchar devname[16]; /* Device name */ |
44 | ulong devoff; /* Device offset */ | |
45 | ulong env_size; /* environment size */ | |
46 | ulong erase_size; /* device erase size */ | |
6aff3115 WD |
47 | } envdev_t; |
48 | ||
49 | static envdev_t envdevices[2]; | |
50 | static int curdev; | |
51 | ||
52 | #define DEVNAME(i) envdevices[(i)].devname | |
d0fb80c3 | 53 | #define DEVOFFSET(i) envdevices[(i)].devoff |
6aff3115 WD |
54 | #define ENVSIZE(i) envdevices[(i)].env_size |
55 | #define DEVESIZE(i) envdevices[(i)].erase_size | |
56 | ||
57 | #define CFG_ENV_SIZE ENVSIZE(curdev) | |
58 | ||
d0fb80c3 | 59 | #define ENV_SIZE getenvsize() |
6aff3115 WD |
60 | |
61 | typedef struct environment_s { | |
4a6fd34b WD |
62 | ulong crc; /* CRC32 over data bytes */ |
63 | uchar flags; /* active or obsolete */ | |
6aff3115 WD |
64 | uchar *data; |
65 | } env_t; | |
66 | ||
67 | static env_t environment; | |
6aff3115 | 68 | |
d0fb80c3 WD |
69 | static int HaveRedundEnv = 0; |
70 | ||
6aff3115 WD |
71 | static uchar active_flag = 1; |
72 | static uchar obsolete_flag = 0; | |
d0fb80c3 | 73 | |
6aff3115 WD |
74 | |
75 | #define XMK_STR(x) #x | |
76 | #define MK_STR(x) XMK_STR(x) | |
77 | ||
78 | static uchar default_environment[] = { | |
d0fb80c3 | 79 | #if defined(CONFIG_BOOTARGS) |
4a6fd34b | 80 | "bootargs=" CONFIG_BOOTARGS "\0" |
6aff3115 | 81 | #endif |
d0fb80c3 | 82 | #if defined(CONFIG_BOOTCOMMAND) |
4a6fd34b | 83 | "bootcmd=" CONFIG_BOOTCOMMAND "\0" |
6aff3115 | 84 | #endif |
d0fb80c3 | 85 | #if defined(CONFIG_RAMBOOTCOMMAND) |
4a6fd34b | 86 | "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" |
d0fb80c3 WD |
87 | #endif |
88 | #if defined(CONFIG_NFSBOOTCOMMAND) | |
4a6fd34b | 89 | "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0" |
d0fb80c3 WD |
90 | #endif |
91 | #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) | |
4a6fd34b | 92 | "bootdelay=" MK_STR (CONFIG_BOOTDELAY) "\0" |
6aff3115 | 93 | #endif |
d0fb80c3 | 94 | #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0) |
4a6fd34b | 95 | "baudrate=" MK_STR (CONFIG_BAUDRATE) "\0" |
6aff3115 | 96 | #endif |
d0fb80c3 | 97 | #ifdef CONFIG_LOADS_ECHO |
4a6fd34b | 98 | "loads_echo=" MK_STR (CONFIG_LOADS_ECHO) "\0" |
d0fb80c3 | 99 | #endif |
6aff3115 | 100 | #ifdef CONFIG_ETHADDR |
4a6fd34b | 101 | "ethaddr=" MK_STR (CONFIG_ETHADDR) "\0" |
6aff3115 | 102 | #endif |
d0fb80c3 | 103 | #ifdef CONFIG_ETH1ADDR |
4a6fd34b | 104 | "eth1addr=" MK_STR (CONFIG_ETH1ADDR) "\0" |
d0fb80c3 WD |
105 | #endif |
106 | #ifdef CONFIG_ETH2ADDR | |
4a6fd34b | 107 | "eth2addr=" MK_STR (CONFIG_ETH2ADDR) "\0" |
d0fb80c3 WD |
108 | #endif |
109 | #ifdef CONFIG_ETHPRIME | |
4a6fd34b | 110 | "ethprime=" CONFIG_ETHPRIME "\0" |
d0fb80c3 | 111 | #endif |
6aff3115 | 112 | #ifdef CONFIG_IPADDR |
4a6fd34b | 113 | "ipaddr=" MK_STR (CONFIG_IPADDR) "\0" |
6aff3115 WD |
114 | #endif |
115 | #ifdef CONFIG_SERVERIP | |
4a6fd34b | 116 | "serverip=" MK_STR (CONFIG_SERVERIP) "\0" |
6aff3115 | 117 | #endif |
d0fb80c3 | 118 | #ifdef CFG_AUTOLOAD |
4a6fd34b | 119 | "autoload=" CFG_AUTOLOAD "\0" |
d0fb80c3 WD |
120 | #endif |
121 | #ifdef CONFIG_ROOTPATH | |
4a6fd34b | 122 | "rootpath=" MK_STR (CONFIG_ROOTPATH) "\0" |
d0fb80c3 WD |
123 | #endif |
124 | #ifdef CONFIG_GATEWAYIP | |
4a6fd34b | 125 | "gatewayip=" MK_STR (CONFIG_GATEWAYIP) "\0" |
d0fb80c3 WD |
126 | #endif |
127 | #ifdef CONFIG_NETMASK | |
4a6fd34b | 128 | "netmask=" MK_STR (CONFIG_NETMASK) "\0" |
d0fb80c3 WD |
129 | #endif |
130 | #ifdef CONFIG_HOSTNAME | |
4a6fd34b | 131 | "hostname=" MK_STR (CONFIG_HOSTNAME) "\0" |
d0fb80c3 WD |
132 | #endif |
133 | #ifdef CONFIG_BOOTFILE | |
4a6fd34b | 134 | "bootfile=" MK_STR (CONFIG_BOOTFILE) "\0" |
d0fb80c3 WD |
135 | #endif |
136 | #ifdef CONFIG_LOADADDR | |
4a6fd34b | 137 | "loadaddr=" MK_STR (CONFIG_LOADADDR) "\0" |
d0fb80c3 WD |
138 | #endif |
139 | #ifdef CONFIG_PREBOOT | |
4a6fd34b | 140 | "preboot=" CONFIG_PREBOOT "\0" |
d0fb80c3 WD |
141 | #endif |
142 | #ifdef CONFIG_CLOCKS_IN_MHZ | |
4a6fd34b | 143 | "clocks_in_mhz=" "1" "\0" |
d0fb80c3 | 144 | #endif |
ad10dd9a | 145 | #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0) |
4a6fd34b | 146 | "pcidelay=" MK_STR (CONFIG_PCI_BOOTDELAY) "\0" |
ad10dd9a | 147 | #endif |
d0fb80c3 WD |
148 | #ifdef CONFIG_EXTRA_ENV_SETTINGS |
149 | CONFIG_EXTRA_ENV_SETTINGS | |
150 | #endif | |
4a6fd34b | 151 | "\0" /* Termimate env_t data with 2 NULs */ |
6aff3115 WD |
152 | }; |
153 | ||
4a6fd34b WD |
154 | static int flash_io (int mode); |
155 | static uchar *envmatch (uchar * s1, uchar * s2); | |
156 | static int env_init (void); | |
157 | static int parse_config (void); | |
158 | ||
d0fb80c3 | 159 | #if defined(CONFIG_FILE) |
4a6fd34b | 160 | static int get_config (char *); |
d0fb80c3 | 161 | #endif |
4a6fd34b | 162 | static inline ulong getenvsize (void) |
d0fb80c3 | 163 | { |
4a6fd34b WD |
164 | ulong rc = CFG_ENV_SIZE - sizeof (long); |
165 | ||
d0fb80c3 | 166 | if (HaveRedundEnv) |
4a6fd34b | 167 | rc -= sizeof (char); |
d0fb80c3 WD |
168 | return rc; |
169 | } | |
6aff3115 WD |
170 | |
171 | /* | |
172 | * Search the environment for a variable. | |
173 | * Return the value, if found, or NULL, if not found. | |
174 | */ | |
175 | unsigned char *fw_getenv (unsigned char *name) | |
176 | { | |
177 | uchar *env, *nxt; | |
178 | ||
4a6fd34b | 179 | if (env_init ()) |
6aff3115 WD |
180 | return (NULL); |
181 | ||
4a6fd34b | 182 | for (env = environment.data; *env; env = nxt + 1) { |
6aff3115 WD |
183 | uchar *val; |
184 | ||
4a6fd34b | 185 | for (nxt = env; *nxt; ++nxt) { |
6aff3115 WD |
186 | if (nxt >= &environment.data[ENV_SIZE]) { |
187 | fprintf (stderr, "## Error: " | |
188 | "environment not terminated\n"); | |
189 | return (NULL); | |
190 | } | |
191 | } | |
4a6fd34b | 192 | val = envmatch (name, env); |
6aff3115 WD |
193 | if (!val) |
194 | continue; | |
195 | return (val); | |
196 | } | |
197 | return (NULL); | |
198 | } | |
199 | ||
200 | /* | |
201 | * Print the current definition of one, or more, or all | |
202 | * environment variables | |
203 | */ | |
4a6fd34b | 204 | void fw_printenv (int argc, char *argv[]) |
6aff3115 WD |
205 | { |
206 | uchar *env, *nxt; | |
207 | int i, n_flag; | |
208 | ||
4a6fd34b | 209 | if (env_init ()) |
6aff3115 WD |
210 | return; |
211 | ||
4a6fd34b WD |
212 | if (argc == 1) { /* Print all env variables */ |
213 | for (env = environment.data; *env; env = nxt + 1) { | |
214 | for (nxt = env; *nxt; ++nxt) { | |
6aff3115 WD |
215 | if (nxt >= &environment.data[ENV_SIZE]) { |
216 | fprintf (stderr, "## Error: " | |
217 | "environment not terminated\n"); | |
218 | return; | |
219 | } | |
220 | } | |
221 | ||
4a6fd34b | 222 | printf ("%s\n", env); |
6aff3115 WD |
223 | } |
224 | return; | |
225 | } | |
226 | ||
4a6fd34b | 227 | if (strcmp (argv[1], "-n") == 0) { |
6aff3115 WD |
228 | n_flag = 1; |
229 | ++argv; | |
230 | --argc; | |
231 | if (argc != 2) { | |
232 | fprintf (stderr, "## Error: " | |
233 | "`-n' option requires exactly one argument\n"); | |
234 | return; | |
235 | } | |
236 | } else { | |
237 | n_flag = 0; | |
238 | } | |
239 | ||
4a6fd34b | 240 | for (i = 1; i < argc; ++i) { /* print single env variables */ |
6aff3115 WD |
241 | uchar *name = argv[i]; |
242 | uchar *val = NULL; | |
243 | ||
4a6fd34b | 244 | for (env = environment.data; *env; env = nxt + 1) { |
6aff3115 | 245 | |
4a6fd34b | 246 | for (nxt = env; *nxt; ++nxt) { |
6aff3115 WD |
247 | if (nxt >= &environment.data[ENV_SIZE]) { |
248 | fprintf (stderr, "## Error: " | |
249 | "environment not terminated\n"); | |
250 | return; | |
251 | } | |
252 | } | |
4a6fd34b | 253 | val = envmatch (name, env); |
6aff3115 WD |
254 | if (val) { |
255 | if (!n_flag) { | |
256 | fputs (name, stdout); | |
4a6fd34b | 257 | putc ('=', stdout); |
6aff3115 | 258 | } |
4a6fd34b | 259 | puts (val); |
6aff3115 WD |
260 | break; |
261 | } | |
262 | } | |
263 | if (!val) | |
4a6fd34b | 264 | fprintf (stderr, "## Error: \"%s\" not defined\n", name); |
6aff3115 WD |
265 | } |
266 | } | |
267 | ||
268 | /* | |
269 | * Deletes or sets environment variables. Returns errno style error codes: | |
270 | * 0 - OK | |
271 | * EINVAL - need at least 1 argument | |
272 | * EROFS - certain variables ("ethaddr", "serial#") cannot be | |
273 | * modified or deleted | |
274 | * | |
275 | */ | |
276 | int fw_setenv (int argc, char *argv[]) | |
277 | { | |
4a6fd34b | 278 | int i, len; |
6aff3115 WD |
279 | uchar *env, *nxt; |
280 | uchar *oldval = NULL; | |
281 | uchar *name; | |
282 | ||
283 | if (argc < 2) { | |
284 | return (EINVAL); | |
285 | } | |
286 | ||
4a6fd34b | 287 | if (env_init ()) |
6aff3115 WD |
288 | return (errno); |
289 | ||
290 | name = argv[1]; | |
291 | ||
292 | /* | |
293 | * search if variable with this name already exists | |
294 | */ | |
4a6fd34b WD |
295 | for (nxt = env = environment.data; *env; env = nxt + 1) { |
296 | for (nxt = env; *nxt; ++nxt) { | |
6aff3115 WD |
297 | if (nxt >= &environment.data[ENV_SIZE]) { |
298 | fprintf (stderr, "## Error: " | |
299 | "environment not terminated\n"); | |
300 | return (EINVAL); | |
301 | } | |
302 | } | |
4a6fd34b | 303 | if ((oldval = envmatch (name, env)) != NULL) |
6aff3115 WD |
304 | break; |
305 | } | |
306 | ||
307 | /* | |
308 | * Delete any existing definition | |
309 | */ | |
310 | if (oldval) { | |
311 | /* | |
312 | * Ethernet Address and serial# can be set only once | |
313 | */ | |
314 | if ((strcmp (name, "ethaddr") == 0) || | |
4a6fd34b | 315 | (strcmp (name, "serial#") == 0)) { |
6aff3115 WD |
316 | fprintf (stderr, "Can't overwrite \"%s\"\n", name); |
317 | return (EROFS); | |
318 | } | |
319 | ||
320 | if (*++nxt == '\0') { | |
321 | *env = '\0'; | |
322 | } else { | |
323 | for (;;) { | |
324 | *env = *nxt++; | |
325 | if ((*env == '\0') && (*nxt == '\0')) | |
326 | break; | |
327 | ++env; | |
328 | } | |
329 | } | |
330 | *++env = '\0'; | |
331 | } | |
332 | ||
333 | /* Delete only ? */ | |
334 | if (argc < 3) | |
335 | goto WRITE_FLASH; | |
336 | ||
337 | /* | |
338 | * Append new definition at the end | |
339 | */ | |
4a6fd34b | 340 | for (env = environment.data; *env || *(env + 1); ++env); |
6aff3115 WD |
341 | if (env > environment.data) |
342 | ++env; | |
343 | /* | |
344 | * Overflow when: | |
345 | * "name" + "=" + "val" +"\0\0" > CFG_ENV_SIZE - (env-environment) | |
346 | */ | |
4a6fd34b | 347 | len = strlen (name) + 2; |
6aff3115 | 348 | /* add '=' for first arg, ' ' for all others */ |
4a6fd34b WD |
349 | for (i = 2; i < argc; ++i) { |
350 | len += strlen (argv[i]) + 1; | |
6aff3115 | 351 | } |
4a6fd34b | 352 | if (len > (&environment.data[ENV_SIZE] - env)) { |
6aff3115 WD |
353 | fprintf (stderr, |
354 | "Error: environment overflow, \"%s\" deleted\n", | |
355 | name); | |
356 | return (-1); | |
357 | } | |
358 | while ((*env = *name++) != '\0') | |
359 | env++; | |
4a6fd34b | 360 | for (i = 2; i < argc; ++i) { |
6aff3115 WD |
361 | uchar *val = argv[i]; |
362 | ||
4a6fd34b WD |
363 | *env = (i == 2) ? '=' : ' '; |
364 | while ((*++env = *val++) != '\0'); | |
6aff3115 WD |
365 | } |
366 | ||
367 | /* end is marked with double '\0' */ | |
368 | *++env = '\0'; | |
369 | ||
4a6fd34b | 370 | WRITE_FLASH: |
6aff3115 WD |
371 | |
372 | /* Update CRC */ | |
4a6fd34b | 373 | environment.crc = crc32 (0, environment.data, ENV_SIZE); |
6aff3115 WD |
374 | |
375 | /* write environment back to flash */ | |
376 | if (flash_io (O_RDWR)) { | |
4a6fd34b | 377 | fprintf (stderr, "Error: can't write fw_env to flash\n"); |
6aff3115 WD |
378 | return (-1); |
379 | } | |
380 | ||
381 | return (0); | |
382 | } | |
383 | ||
384 | static int flash_io (int mode) | |
385 | { | |
386 | int fd, fdr, rc, otherdev, len, resid; | |
387 | erase_info_t erase; | |
592c5cab | 388 | char *data = NULL; |
6aff3115 | 389 | |
4a6fd34b WD |
390 | if ((fd = open (DEVNAME (curdev), mode)) < 0) { |
391 | fprintf (stderr, | |
392 | "Can't open %s: %s\n", | |
393 | DEVNAME (curdev), strerror (errno)); | |
6aff3115 WD |
394 | return (-1); |
395 | } | |
396 | ||
4a6fd34b | 397 | len = sizeof (environment.crc); |
d0fb80c3 | 398 | if (HaveRedundEnv) { |
4a6fd34b | 399 | len += sizeof (environment.flags); |
d0fb80c3 | 400 | } |
6aff3115 WD |
401 | |
402 | if (mode == O_RDWR) { | |
d0fb80c3 WD |
403 | if (HaveRedundEnv) { |
404 | /* switch to next partition for writing */ | |
405 | otherdev = !curdev; | |
4a6fd34b WD |
406 | if ((fdr = open (DEVNAME (otherdev), mode)) < 0) { |
407 | fprintf (stderr, | |
408 | "Can't open %s: %s\n", | |
409 | DEVNAME (otherdev), | |
410 | strerror (errno)); | |
d0fb80c3 WD |
411 | return (-1); |
412 | } | |
413 | } else { | |
414 | otherdev = curdev; | |
415 | fdr = fd; | |
6aff3115 | 416 | } |
4a6fd34b WD |
417 | printf ("Unlocking flash...\n"); |
418 | erase.length = DEVESIZE (otherdev); | |
419 | erase.start = DEVOFFSET (otherdev); | |
6aff3115 WD |
420 | ioctl (fdr, MEMUNLOCK, &erase); |
421 | ||
d0fb80c3 | 422 | if (HaveRedundEnv) { |
4a6fd34b WD |
423 | erase.length = DEVESIZE (curdev); |
424 | erase.start = DEVOFFSET (curdev); | |
d0fb80c3 WD |
425 | ioctl (fd, MEMUNLOCK, &erase); |
426 | environment.flags = active_flag; | |
427 | } | |
428 | ||
4a6fd34b WD |
429 | printf ("Done\n"); |
430 | resid = DEVESIZE (otherdev) - CFG_ENV_SIZE; | |
6aff3115 | 431 | if (resid) { |
4a6fd34b WD |
432 | if ((data = malloc (resid)) == NULL) { |
433 | fprintf (stderr, | |
434 | "Cannot malloc %d bytes: %s\n", | |
435 | resid, | |
436 | strerror (errno)); | |
6aff3115 WD |
437 | return (-1); |
438 | } | |
4a6fd34b WD |
439 | if (lseek (fdr, DEVOFFSET (otherdev) + CFG_ENV_SIZE, SEEK_SET) |
440 | == -1) { | |
441 | fprintf (stderr, "seek error on %s: %s\n", | |
442 | DEVNAME (otherdev), | |
443 | strerror (errno)); | |
6aff3115 WD |
444 | return (-1); |
445 | } | |
446 | if ((rc = read (fdr, data, resid)) != resid) { | |
447 | fprintf (stderr, | |
4a6fd34b WD |
448 | "read error on %s: %s\n", |
449 | DEVNAME (otherdev), | |
450 | strerror (errno)); | |
6aff3115 WD |
451 | return (-1); |
452 | } | |
453 | } | |
454 | ||
4a6fd34b | 455 | printf ("Erasing old environment...\n"); |
6aff3115 | 456 | |
4a6fd34b WD |
457 | erase.length = DEVESIZE (otherdev); |
458 | erase.start = DEVOFFSET (otherdev); | |
6aff3115 WD |
459 | if (ioctl (fdr, MEMERASE, &erase) != 0) { |
460 | fprintf (stderr, "MTD erase error on %s: %s\n", | |
4a6fd34b WD |
461 | DEVNAME (otherdev), |
462 | strerror (errno)); | |
6aff3115 WD |
463 | return (-1); |
464 | } | |
465 | ||
4a6fd34b | 466 | printf ("Done\n"); |
6aff3115 | 467 | |
4a6fd34b WD |
468 | printf ("Writing environment to %s...\n", DEVNAME (otherdev)); |
469 | if (lseek (fdr, DEVOFFSET (otherdev), SEEK_SET) == -1) { | |
d0fb80c3 | 470 | fprintf (stderr, |
4a6fd34b WD |
471 | "seek error on %s: %s\n", |
472 | DEVNAME (otherdev), strerror (errno)); | |
d0fb80c3 WD |
473 | return (-1); |
474 | } | |
4a6fd34b | 475 | if (write (fdr, &environment, len) != len) { |
6aff3115 | 476 | fprintf (stderr, |
4a6fd34b WD |
477 | "CRC write error on %s: %s\n", |
478 | DEVNAME (otherdev), strerror (errno)); | |
6aff3115 WD |
479 | return (-1); |
480 | } | |
4a6fd34b | 481 | if (write (fdr, environment.data, ENV_SIZE) != ENV_SIZE) { |
6aff3115 | 482 | fprintf (stderr, |
4a6fd34b WD |
483 | "Write error on %s: %s\n", |
484 | DEVNAME (otherdev), strerror (errno)); | |
6aff3115 WD |
485 | return (-1); |
486 | } | |
487 | if (resid) { | |
488 | if (write (fdr, data, resid) != resid) { | |
489 | fprintf (stderr, | |
4a6fd34b WD |
490 | "write error on %s: %s\n", |
491 | DEVNAME (curdev), strerror (errno)); | |
6aff3115 WD |
492 | return (-1); |
493 | } | |
4a6fd34b | 494 | free (data); |
6aff3115 | 495 | } |
d0fb80c3 WD |
496 | if (HaveRedundEnv) { |
497 | /* change flag on current active env partition */ | |
4a6fd34b WD |
498 | if (lseek (fd, DEVOFFSET (curdev) + sizeof (ulong), SEEK_SET) |
499 | == -1) { | |
500 | fprintf (stderr, "seek error on %s: %s\n", | |
501 | DEVNAME (curdev), strerror (errno)); | |
d0fb80c3 WD |
502 | return (-1); |
503 | } | |
4a6fd34b WD |
504 | if (write (fd, &obsolete_flag, sizeof (obsolete_flag)) != |
505 | sizeof (obsolete_flag)) { | |
d0fb80c3 | 506 | fprintf (stderr, |
4a6fd34b WD |
507 | "Write error on %s: %s\n", |
508 | DEVNAME (curdev), strerror (errno)); | |
d0fb80c3 WD |
509 | return (-1); |
510 | } | |
6aff3115 | 511 | } |
4a6fd34b WD |
512 | printf ("Done\n"); |
513 | printf ("Locking ...\n"); | |
514 | erase.length = DEVESIZE (otherdev); | |
515 | erase.start = DEVOFFSET (otherdev); | |
6aff3115 | 516 | ioctl (fdr, MEMLOCK, &erase); |
d0fb80c3 | 517 | if (HaveRedundEnv) { |
4a6fd34b WD |
518 | erase.length = DEVESIZE (curdev); |
519 | erase.start = DEVOFFSET (curdev); | |
d0fb80c3 | 520 | ioctl (fd, MEMLOCK, &erase); |
4a6fd34b | 521 | if (close (fdr)) { |
d0fb80c3 | 522 | fprintf (stderr, |
4a6fd34b WD |
523 | "I/O error on %s: %s\n", |
524 | DEVNAME (otherdev), | |
525 | strerror (errno)); | |
d0fb80c3 WD |
526 | return (-1); |
527 | } | |
6aff3115 | 528 | } |
4a6fd34b | 529 | printf ("Done\n"); |
6aff3115 | 530 | } else { |
d0fb80c3 | 531 | |
4a6fd34b | 532 | if (lseek (fd, DEVOFFSET (curdev), SEEK_SET) == -1) { |
d0fb80c3 | 533 | fprintf (stderr, |
4a6fd34b WD |
534 | "seek error on %s: %s\n", |
535 | DEVNAME (curdev), strerror (errno)); | |
d0fb80c3 WD |
536 | return (-1); |
537 | } | |
6aff3115 WD |
538 | if (read (fd, &environment, len) != len) { |
539 | fprintf (stderr, | |
4a6fd34b WD |
540 | "CRC read error on %s: %s\n", |
541 | DEVNAME (curdev), strerror (errno)); | |
6aff3115 WD |
542 | return (-1); |
543 | } | |
544 | if ((rc = read (fd, environment.data, ENV_SIZE)) != ENV_SIZE) { | |
545 | fprintf (stderr, | |
4a6fd34b WD |
546 | "Read error on %s: %s\n", |
547 | DEVNAME (curdev), strerror (errno)); | |
6aff3115 WD |
548 | return (-1); |
549 | } | |
550 | } | |
551 | ||
4a6fd34b | 552 | if (close (fd)) { |
6aff3115 | 553 | fprintf (stderr, |
4a6fd34b WD |
554 | "I/O error on %s: %s\n", |
555 | DEVNAME (curdev), strerror (errno)); | |
6aff3115 WD |
556 | return (-1); |
557 | } | |
558 | ||
559 | /* everything ok */ | |
560 | return (0); | |
561 | } | |
562 | ||
563 | /* | |
564 | * s1 is either a simple 'name', or a 'name=value' pair. | |
565 | * s2 is a 'name=value' pair. | |
566 | * If the names match, return the value of s2, else NULL. | |
567 | */ | |
568 | ||
4a6fd34b | 569 | static uchar *envmatch (uchar * s1, uchar * s2) |
6aff3115 WD |
570 | { |
571 | ||
572 | while (*s1 == *s2++) | |
573 | if (*s1++ == '=') | |
4a6fd34b WD |
574 | return (s2); |
575 | if (*s1 == '\0' && *(s2 - 1) == '=') | |
576 | return (s2); | |
577 | return (NULL); | |
6aff3115 WD |
578 | } |
579 | ||
580 | /* | |
581 | * Prevent confusion if running from erased flash memory | |
582 | */ | |
4a6fd34b | 583 | static int env_init (void) |
6aff3115 WD |
584 | { |
585 | int crc1, crc1_ok; | |
586 | uchar *addr1; | |
d0fb80c3 | 587 | |
6aff3115 WD |
588 | int crc2, crc2_ok; |
589 | uchar flag1, flag2, *addr2; | |
6aff3115 | 590 | |
4a6fd34b | 591 | if (parse_config ()) /* should fill envdevices */ |
d0fb80c3 | 592 | return 1; |
4a6fd34b | 593 | |
d0fb80c3 | 594 | if ((addr1 = calloc (1, ENV_SIZE)) == NULL) { |
4a6fd34b WD |
595 | fprintf (stderr, |
596 | "Not enough memory for environment (%ld bytes)\n", | |
597 | ENV_SIZE); | |
d0fb80c3 WD |
598 | return (errno); |
599 | } | |
4a6fd34b | 600 | |
d0fb80c3 WD |
601 | /* read environment from FLASH to local buffer */ |
602 | environment.data = addr1; | |
603 | curdev = 0; | |
604 | if (flash_io (O_RDONLY)) { | |
605 | return (errno); | |
606 | } | |
4a6fd34b WD |
607 | |
608 | crc1_ok = ((crc1 = crc32 (0, environment.data, ENV_SIZE)) | |
d0fb80c3 WD |
609 | == environment.crc); |
610 | if (!HaveRedundEnv) { | |
6aff3115 | 611 | if (!crc1_ok) { |
4a6fd34b WD |
612 | fprintf (stderr, |
613 | "Warning: Bad CRC, using default environment\n"); | |
6aff3115 | 614 | environment.data = default_environment; |
4a6fd34b | 615 | free (addr1); |
6aff3115 | 616 | } |
d0fb80c3 | 617 | } else { |
6aff3115 | 618 | flag1 = environment.flags; |
4a6fd34b | 619 | |
6aff3115 WD |
620 | curdev = 1; |
621 | if ((addr2 = calloc (1, ENV_SIZE)) == NULL) { | |
4a6fd34b WD |
622 | fprintf (stderr, |
623 | "Not enough memory for environment (%ld bytes)\n", | |
624 | ENV_SIZE); | |
6aff3115 | 625 | return (errno); |
4a6fd34b | 626 | } |
6aff3115 | 627 | environment.data = addr2; |
4a6fd34b | 628 | |
6aff3115 WD |
629 | if (flash_io (O_RDONLY)) { |
630 | return (errno); | |
631 | } | |
4a6fd34b WD |
632 | |
633 | crc2_ok = ((crc2 = crc32 (0, environment.data, ENV_SIZE)) | |
6aff3115 WD |
634 | == environment.crc); |
635 | flag2 = environment.flags; | |
4a6fd34b WD |
636 | |
637 | if (crc1_ok && !crc2_ok) { | |
638 | environment.data = addr1; | |
6aff3115 WD |
639 | environment.flags = flag1; |
640 | environment.crc = crc1; | |
641 | curdev = 0; | |
4a6fd34b WD |
642 | free (addr2); |
643 | } else if (!crc1_ok && crc2_ok) { | |
644 | environment.data = addr2; | |
6aff3115 WD |
645 | environment.flags = flag2; |
646 | environment.crc = crc2; | |
647 | curdev = 1; | |
4a6fd34b WD |
648 | free (addr1); |
649 | } else if (!crc1_ok && !crc2_ok) { | |
650 | fprintf (stderr, | |
651 | "Warning: Bad CRC, using default environment\n"); | |
6aff3115 WD |
652 | environment.data = default_environment; |
653 | curdev = 0; | |
4a6fd34b WD |
654 | free (addr2); |
655 | free (addr1); | |
656 | } else if (flag1 == active_flag && flag2 == obsolete_flag) { | |
657 | environment.data = addr1; | |
6aff3115 WD |
658 | environment.flags = flag1; |
659 | environment.crc = crc1; | |
660 | curdev = 0; | |
4a6fd34b WD |
661 | free (addr2); |
662 | } else if (flag1 == obsolete_flag && flag2 == active_flag) { | |
663 | environment.data = addr2; | |
6aff3115 WD |
664 | environment.flags = flag2; |
665 | environment.crc = crc2; | |
666 | curdev = 1; | |
4a6fd34b WD |
667 | free (addr1); |
668 | } else if (flag1 == flag2) { | |
669 | environment.data = addr1; | |
6aff3115 WD |
670 | environment.flags = flag1; |
671 | environment.crc = crc1; | |
672 | curdev = 0; | |
4a6fd34b WD |
673 | free (addr2); |
674 | } else if (flag1 == 0xFF) { | |
675 | environment.data = addr1; | |
6aff3115 WD |
676 | environment.flags = flag1; |
677 | environment.crc = crc1; | |
678 | curdev = 0; | |
4a6fd34b WD |
679 | free (addr2); |
680 | } else if (flag2 == 0xFF) { | |
681 | environment.data = addr2; | |
6aff3115 WD |
682 | environment.flags = flag2; |
683 | environment.crc = crc2; | |
684 | curdev = 1; | |
4a6fd34b | 685 | free (addr1); |
6aff3115 | 686 | } |
6aff3115 WD |
687 | } |
688 | return (0); | |
689 | } | |
690 | ||
691 | ||
4a6fd34b | 692 | static int parse_config () |
6aff3115 WD |
693 | { |
694 | struct stat st; | |
695 | ||
d0fb80c3 WD |
696 | #if defined(CONFIG_FILE) |
697 | /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ | |
4a6fd34b | 698 | if (get_config (CONFIG_FILE)) { |
d0fb80c3 | 699 | fprintf (stderr, |
4a6fd34b | 700 | "Cannot parse config file: %s\n", strerror (errno)); |
6aff3115 WD |
701 | return 1; |
702 | } | |
d0fb80c3 | 703 | #else |
4a6fd34b WD |
704 | strcpy (DEVNAME (0), DEVICE1_NAME); |
705 | DEVOFFSET (0) = DEVICE1_OFFSET; | |
706 | ENVSIZE (0) = ENV1_SIZE; | |
707 | DEVESIZE (0) = DEVICE1_ESIZE; | |
6aff3115 | 708 | #ifdef HAVE_REDUND |
4a6fd34b WD |
709 | strcpy (DEVNAME (1), DEVICE2_NAME); |
710 | DEVOFFSET (1) = DEVICE2_OFFSET; | |
711 | ENVSIZE (1) = ENV2_SIZE; | |
712 | DEVESIZE (1) = DEVICE2_ESIZE; | |
d0fb80c3 | 713 | HaveRedundEnv = 1; |
6aff3115 | 714 | #endif |
d0fb80c3 | 715 | #endif |
4a6fd34b WD |
716 | if (stat (DEVNAME (0), &st)) { |
717 | fprintf (stderr, | |
718 | "Cannot access MTD device %s: %s\n", | |
719 | DEVNAME (0), strerror (errno)); | |
d0fb80c3 WD |
720 | return 1; |
721 | } | |
4a6fd34b WD |
722 | |
723 | if (HaveRedundEnv && stat (DEVNAME (1), &st)) { | |
724 | fprintf (stderr, | |
725 | "Cannot access MTD device %s: %s\n", | |
726 | DEVNAME (2), strerror (errno)); | |
d0fb80c3 WD |
727 | return 1; |
728 | } | |
6aff3115 WD |
729 | return 0; |
730 | } | |
d0fb80c3 WD |
731 | |
732 | #if defined(CONFIG_FILE) | |
733 | static int get_config (char *fname) | |
734 | { | |
735 | FILE *fp; | |
736 | int i = 0; | |
737 | int rc; | |
738 | char dump[128]; | |
739 | ||
4a6fd34b | 740 | if ((fp = fopen (fname, "r")) == NULL) { |
d0fb80c3 WD |
741 | return 1; |
742 | } | |
743 | ||
4a6fd34b WD |
744 | while ((i < 2) && ((rc = fscanf (fp, "%s %lx %lx %lx", |
745 | DEVNAME (i), | |
746 | &DEVOFFSET (i), | |
747 | &ENVSIZE (i), | |
748 | &DEVESIZE (i) )) != EOF)) { | |
d0fb80c3 WD |
749 | |
750 | /* Skip incomplete conversions and comment strings */ | |
4a6fd34b WD |
751 | if ((rc < 3) || (*DEVNAME (i) == '#')) { |
752 | fgets (dump, sizeof (dump), fp); /* Consume till end */ | |
d0fb80c3 WD |
753 | continue; |
754 | } | |
755 | ||
756 | i++; | |
757 | } | |
4a6fd34b WD |
758 | fclose (fp); |
759 | ||
d0fb80c3 | 760 | HaveRedundEnv = i - 1; |
4a6fd34b | 761 | if (!i) { /* No valid entries found */ |
d0fb80c3 WD |
762 | errno = EINVAL; |
763 | return 1; | |
764 | } else | |
765 | return 0; | |
766 | } | |
767 | #endif |