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