]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/env/fw_env.c
b60395ecbac7ea60de0f9dcb3d51bbaf1cc2478d
[karo-tx-uboot.git] / tools / env / fw_env.c
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