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