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