Merge tag 'dm-pull-3dec19' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm
[oweals/u-boot.git] / tools / env / fw_env.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000-2010
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  *
6  * (C) Copyright 2008
7  * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de.
8  */
9
10 #define _GNU_SOURCE
11
12 #include <compiler.h>
13 #include <env.h>
14 #include <errno.h>
15 #include <env_flags.h>
16 #include <fcntl.h>
17 #include <libgen.h>
18 #include <linux/fs.h>
19 #include <linux/stringify.h>
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <u-boot/crc.h>
29 #include <unistd.h>
30 #include <dirent.h>
31
32 #ifdef MTD_OLD
33 # include <stdint.h>
34 # include <linux/mtd/mtd.h>
35 #else
36 # define  __user        /* nothing */
37 # include <mtd/mtd-user.h>
38 #endif
39
40 #include <mtd/ubi-user.h>
41
42 #include "fw_env_private.h"
43 #include "fw_env.h"
44
45 struct env_opts default_opts = {
46 #ifdef CONFIG_FILE
47         .config_file = CONFIG_FILE
48 #endif
49 };
50
51 #define DIV_ROUND_UP(n, d)      (((n) + (d) - 1) / (d))
52
53 #define min(x, y) ({                            \
54         typeof(x) _min1 = (x);                  \
55         typeof(y) _min2 = (y);                  \
56         (void) (&_min1 == &_min2);              \
57         _min1 < _min2 ? _min1 : _min2; })
58
59 struct envdev_s {
60         const char *devname;            /* Device name */
61         long long devoff;               /* Device offset */
62         ulong env_size;                 /* environment size */
63         ulong erase_size;               /* device erase size */
64         ulong env_sectors;              /* number of environment sectors */
65         uint8_t mtd_type;               /* type of the MTD device */
66         int is_ubi;                     /* set if we use UBI volume */
67 };
68
69 static struct envdev_s envdevices[2] = {
70         {
71                 .mtd_type = MTD_ABSENT,
72         }, {
73                 .mtd_type = MTD_ABSENT,
74         },
75 };
76
77 static int dev_current;
78
79 #define DEVNAME(i)    envdevices[(i)].devname
80 #define DEVOFFSET(i)  envdevices[(i)].devoff
81 #define ENVSIZE(i)    envdevices[(i)].env_size
82 #define DEVESIZE(i)   envdevices[(i)].erase_size
83 #define ENVSECTORS(i) envdevices[(i)].env_sectors
84 #define DEVTYPE(i)    envdevices[(i)].mtd_type
85 #define IS_UBI(i)     envdevices[(i)].is_ubi
86
87 #define CUR_ENVSIZE ENVSIZE(dev_current)
88
89 static unsigned long usable_envsize;
90 #define ENV_SIZE      usable_envsize
91
92 struct env_image_single {
93         uint32_t crc;           /* CRC32 over data bytes    */
94         char data[];
95 };
96
97 struct env_image_redundant {
98         uint32_t crc;           /* CRC32 over data bytes    */
99         unsigned char flags;    /* active or obsolete */
100         char data[];
101 };
102
103 enum flag_scheme {
104         FLAG_NONE,
105         FLAG_BOOLEAN,
106         FLAG_INCREMENTAL,
107 };
108
109 struct environment {
110         void *image;
111         uint32_t *crc;
112         unsigned char *flags;
113         char *data;
114         enum flag_scheme flag_scheme;
115 };
116
117 static struct environment environment = {
118         .flag_scheme = FLAG_NONE,
119 };
120
121 static int have_redund_env;
122
123 #define DEFAULT_ENV_INSTANCE_STATIC
124 #include <env_default.h>
125
126 #define UBI_DEV_START "/dev/ubi"
127 #define UBI_SYSFS "/sys/class/ubi"
128 #define UBI_VOL_NAME_PATT "ubi%d_%d"
129
130 static int is_ubi_devname(const char *devname)
131 {
132         return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1);
133 }
134
135 static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name,
136                                        const char *volname)
137 {
138         char path[256];
139         FILE *file;
140         char *name;
141         int ret;
142
143         strcpy(path, UBI_SYSFS "/");
144         strcat(path, volume_sysfs_name);
145         strcat(path, "/name");
146
147         file = fopen(path, "r");
148         if (!file)
149                 return -1;
150
151         ret = fscanf(file, "%ms", &name);
152         fclose(file);
153         if (ret <= 0 || !name) {
154                 fprintf(stderr,
155                         "Failed to read from file %s, ret = %d, name = %s\n",
156                         path, ret, name);
157                 return -1;
158         }
159
160         if (!strcmp(name, volname)) {
161                 free(name);
162                 return 0;
163         }
164         free(name);
165
166         return -1;
167 }
168
169 static int ubi_get_volnum_by_name(int devnum, const char *volname)
170 {
171         DIR *sysfs_ubi;
172         struct dirent *dirent;
173         int ret;
174         int tmp_devnum;
175         int volnum;
176
177         sysfs_ubi = opendir(UBI_SYSFS);
178         if (!sysfs_ubi)
179                 return -1;
180
181 #ifdef DEBUG
182         fprintf(stderr, "Looking for volume name \"%s\"\n", volname);
183 #endif
184
185         while (1) {
186                 dirent = readdir(sysfs_ubi);
187                 if (!dirent)
188                         return -1;
189
190                 ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT,
191                              &tmp_devnum, &volnum);
192                 if (ret == 2 && devnum == tmp_devnum) {
193                         if (ubi_check_volume_sysfs_name(dirent->d_name,
194                                                         volname) == 0)
195                                 return volnum;
196                 }
197         }
198
199         return -1;
200 }
201
202 static int ubi_get_devnum_by_devname(const char *devname)
203 {
204         int devnum;
205         int ret;
206
207         ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum);
208         if (ret != 1)
209                 return -1;
210
211         return devnum;
212 }
213
214 static const char *ubi_get_volume_devname(const char *devname,
215                                           const char *volname)
216 {
217         char *volume_devname;
218         int volnum;
219         int devnum;
220         int ret;
221
222         devnum = ubi_get_devnum_by_devname(devname);
223         if (devnum < 0)
224                 return NULL;
225
226         volnum = ubi_get_volnum_by_name(devnum, volname);
227         if (volnum < 0)
228                 return NULL;
229
230         ret = asprintf(&volume_devname, "%s_%d", devname, volnum);
231         if (ret < 0)
232                 return NULL;
233
234 #ifdef DEBUG
235         fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n",
236                 devname, volname, volume_devname);
237 #endif
238
239         return volume_devname;
240 }
241
242 static void ubi_check_dev(unsigned int dev_id)
243 {
244         char *devname = (char *)DEVNAME(dev_id);
245         char *pname;
246         const char *volname = NULL;
247         const char *volume_devname;
248
249         if (!is_ubi_devname(DEVNAME(dev_id)))
250                 return;
251
252         IS_UBI(dev_id) = 1;
253
254         for (pname = devname; *pname != '\0'; pname++) {
255                 if (*pname == ':') {
256                         *pname = '\0';
257                         volname = pname + 1;
258                         break;
259                 }
260         }
261
262         if (volname) {
263                 /* Let's find real volume device name */
264                 volume_devname = ubi_get_volume_devname(devname, volname);
265                 if (!volume_devname) {
266                         fprintf(stderr, "Didn't found ubi volume \"%s\"\n",
267                                 volname);
268                         return;
269                 }
270
271                 free(devname);
272                 DEVNAME(dev_id) = volume_devname;
273         }
274 }
275
276 static int ubi_update_start(int fd, int64_t bytes)
277 {
278         if (ioctl(fd, UBI_IOCVOLUP, &bytes))
279                 return -1;
280         return 0;
281 }
282
283 static int ubi_read(int fd, void *buf, size_t count)
284 {
285         ssize_t ret;
286
287         while (count > 0) {
288                 ret = read(fd, buf, count);
289                 if (ret > 0) {
290                         count -= ret;
291                         buf += ret;
292
293                         continue;
294                 }
295
296                 if (ret == 0) {
297                         /*
298                          * Happens in case of too short volume data size. If we
299                          * return error status we will fail it will be treated
300                          * as UBI device error.
301                          *
302                          * Leave catching this error to CRC check.
303                          */
304                         fprintf(stderr, "Warning: end of data on ubi volume\n");
305                         return 0;
306                 } else if (errno == EBADF) {
307                         /*
308                          * Happens in case of corrupted volume. The same as
309                          * above, we cannot return error now, as we will still
310                          * be able to successfully write environment later.
311                          */
312                         fprintf(stderr, "Warning: corrupted volume?\n");
313                         return 0;
314                 } else if (errno == EINTR) {
315                         continue;
316                 }
317
318                 fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n",
319                         (unsigned int)count, strerror(errno));
320                 return -1;
321         }
322
323         return 0;
324 }
325
326 static int ubi_write(int fd, const void *buf, size_t count)
327 {
328         ssize_t ret;
329
330         while (count > 0) {
331                 ret = write(fd, buf, count);
332                 if (ret <= 0) {
333                         if (ret < 0 && errno == EINTR)
334                                 continue;
335
336                         fprintf(stderr, "Cannot write %u bytes to ubi volume\n",
337                                 (unsigned int)count);
338                         return -1;
339                 }
340
341                 count -= ret;
342                 buf += ret;
343         }
344
345         return 0;
346 }
347
348 static int flash_io(int mode);
349 static int parse_config(struct env_opts *opts);
350
351 #if defined(CONFIG_FILE)
352 static int get_config(char *);
353 #endif
354
355 static char *skip_chars(char *s)
356 {
357         for (; *s != '\0'; s++) {
358                 if (isblank(*s) || *s == '=')
359                         return s;
360         }
361         return NULL;
362 }
363
364 static char *skip_blanks(char *s)
365 {
366         for (; *s != '\0'; s++) {
367                 if (!isblank(*s))
368                         return s;
369         }
370         return NULL;
371 }
372
373 /*
374  * s1 is either a simple 'name', or a 'name=value' pair.
375  * s2 is a 'name=value' pair.
376  * If the names match, return the value of s2, else NULL.
377  */
378 static char *envmatch(char *s1, char *s2)
379 {
380         if (s1 == NULL || s2 == NULL)
381                 return NULL;
382
383         while (*s1 == *s2++)
384                 if (*s1++ == '=')
385                         return s2;
386         if (*s1 == '\0' && *(s2 - 1) == '=')
387                 return s2;
388         return NULL;
389 }
390
391 /**
392  * Search the environment for a variable.
393  * Return the value, if found, or NULL, if not found.
394  */
395 char *fw_getenv(char *name)
396 {
397         char *env, *nxt;
398
399         for (env = environment.data; *env; env = nxt + 1) {
400                 char *val;
401
402                 for (nxt = env; *nxt; ++nxt) {
403                         if (nxt >= &environment.data[ENV_SIZE]) {
404                                 fprintf(stderr, "## Error: "
405                                         "environment not terminated\n");
406                                 return NULL;
407                         }
408                 }
409                 val = envmatch(name, env);
410                 if (!val)
411                         continue;
412                 return val;
413         }
414         return NULL;
415 }
416
417 /*
418  * Search the default environment for a variable.
419  * Return the value, if found, or NULL, if not found.
420  */
421 char *fw_getdefenv(char *name)
422 {
423         char *env, *nxt;
424
425         for (env = default_environment; *env; env = nxt + 1) {
426                 char *val;
427
428                 for (nxt = env; *nxt; ++nxt) {
429                         if (nxt >= &default_environment[ENV_SIZE]) {
430                                 fprintf(stderr, "## Error: "
431                                         "default environment not terminated\n");
432                                 return NULL;
433                         }
434                 }
435                 val = envmatch(name, env);
436                 if (!val)
437                         continue;
438                 return val;
439         }
440         return NULL;
441 }
442
443 /*
444  * Print the current definition of one, or more, or all
445  * environment variables
446  */
447 int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
448 {
449         int i, rc = 0;
450
451         if (value_only && argc != 1) {
452                 fprintf(stderr,
453                         "## Error: `-n'/`--noheader' option requires exactly one argument\n");
454                 return -1;
455         }
456
457         if (!opts)
458                 opts = &default_opts;
459
460         if (fw_env_open(opts))
461                 return -1;
462
463         if (argc == 0) {        /* Print all env variables  */
464                 char *env, *nxt;
465                 for (env = environment.data; *env; env = nxt + 1) {
466                         for (nxt = env; *nxt; ++nxt) {
467                                 if (nxt >= &environment.data[ENV_SIZE]) {
468                                         fprintf(stderr, "## Error: "
469                                                 "environment not terminated\n");
470                                         return -1;
471                                 }
472                         }
473
474                         printf("%s\n", env);
475                 }
476                 fw_env_close(opts);
477                 return 0;
478         }
479
480         for (i = 0; i < argc; ++i) {    /* print a subset of env variables */
481                 char *name = argv[i];
482                 char *val = NULL;
483
484                 val = fw_getenv(name);
485                 if (!val) {
486                         fprintf(stderr, "## Error: \"%s\" not defined\n", name);
487                         rc = -1;
488                         continue;
489                 }
490
491                 if (value_only) {
492                         puts(val);
493                         break;
494                 }
495
496                 printf("%s=%s\n", name, val);
497         }
498
499         fw_env_close(opts);
500
501         return rc;
502 }
503
504 int fw_env_flush(struct env_opts *opts)
505 {
506         if (!opts)
507                 opts = &default_opts;
508
509         /*
510          * Update CRC
511          */
512         *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
513
514         /* write environment back to flash */
515         if (flash_io(O_RDWR)) {
516                 fprintf(stderr, "Error: can't write fw_env to flash\n");
517                 return -1;
518         }
519
520         return 0;
521 }
522
523 /*
524  * Set/Clear a single variable in the environment.
525  * This is called in sequence to update the environment
526  * in RAM without updating the copy in flash after each set
527  */
528 int fw_env_write(char *name, char *value)
529 {
530         int len;
531         char *env, *nxt;
532         char *oldval = NULL;
533         int deleting, creating, overwriting;
534
535         /*
536          * search if variable with this name already exists
537          */
538         for (nxt = env = environment.data; *env; env = nxt + 1) {
539                 for (nxt = env; *nxt; ++nxt) {
540                         if (nxt >= &environment.data[ENV_SIZE]) {
541                                 fprintf(stderr, "## Error: "
542                                         "environment not terminated\n");
543                                 errno = EINVAL;
544                                 return -1;
545                         }
546                 }
547                 oldval = envmatch(name, env);
548                 if (oldval)
549                         break;
550         }
551
552         deleting = (oldval && !(value && strlen(value)));
553         creating = (!oldval && (value && strlen(value)));
554         overwriting = (oldval && (value && strlen(value)));
555
556         /* check for permission */
557         if (deleting) {
558                 if (env_flags_validate_varaccess(name,
559                     ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
560                         printf("Can't delete \"%s\"\n", name);
561                         errno = EROFS;
562                         return -1;
563                 }
564         } else if (overwriting) {
565                 if (env_flags_validate_varaccess(name,
566                     ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
567                         printf("Can't overwrite \"%s\"\n", name);
568                         errno = EROFS;
569                         return -1;
570                 } else if (env_flags_validate_varaccess(name,
571                            ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
572                         const char *defval = fw_getdefenv(name);
573
574                         if (defval == NULL)
575                                 defval = "";
576                         if (strcmp(oldval, defval)
577                             != 0) {
578                                 printf("Can't overwrite \"%s\"\n", name);
579                                 errno = EROFS;
580                                 return -1;
581                         }
582                 }
583         } else if (creating) {
584                 if (env_flags_validate_varaccess(name,
585                     ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
586                         printf("Can't create \"%s\"\n", name);
587                         errno = EROFS;
588                         return -1;
589                 }
590         } else
591                 /* Nothing to do */
592                 return 0;
593
594         if (deleting || overwriting) {
595                 if (*++nxt == '\0') {
596                         *env = '\0';
597                 } else {
598                         for (;;) {
599                                 *env = *nxt++;
600                                 if ((*env == '\0') && (*nxt == '\0'))
601                                         break;
602                                 ++env;
603                         }
604                 }
605                 *++env = '\0';
606         }
607
608         /* Delete only ? */
609         if (!value || !strlen(value))
610                 return 0;
611
612         /*
613          * Append new definition at the end
614          */
615         for (env = environment.data; *env || *(env + 1); ++env)
616                 ;
617         if (env > environment.data)
618                 ++env;
619         /*
620          * Overflow when:
621          * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
622          */
623         len = strlen(name) + 2;
624         /* add '=' for first arg, ' ' for all others */
625         len += strlen(value) + 1;
626
627         if (len > (&environment.data[ENV_SIZE] - env)) {
628                 fprintf(stderr,
629                         "Error: environment overflow, \"%s\" deleted\n", name);
630                 return -1;
631         }
632
633         while ((*env = *name++) != '\0')
634                 env++;
635         *env = '=';
636         while ((*++env = *value++) != '\0')
637                 ;
638
639         /* end is marked with double '\0' */
640         *++env = '\0';
641
642         return 0;
643 }
644
645 /*
646  * Deletes or sets environment variables. Returns -1 and sets errno error codes:
647  * 0      - OK
648  * EINVAL - need at least 1 argument
649  * EROFS  - certain variables ("ethaddr", "serial#") cannot be
650  *          modified or deleted
651  *
652  */
653 int fw_env_set(int argc, char *argv[], struct env_opts *opts)
654 {
655         int i;
656         size_t len;
657         char *name, **valv;
658         char *oldval;
659         char *value = NULL;
660         int valc;
661         int ret;
662
663         if (!opts)
664                 opts = &default_opts;
665
666         if (argc < 1) {
667                 fprintf(stderr, "## Error: variable name missing\n");
668                 errno = EINVAL;
669                 return -1;
670         }
671
672         if (fw_env_open(opts)) {
673                 fprintf(stderr, "Error: environment not initialized\n");
674                 return -1;
675         }
676
677         name = argv[0];
678         valv = argv + 1;
679         valc = argc - 1;
680
681         if (env_flags_validate_env_set_params(name, valv, valc) < 0) {
682                 fw_env_close(opts);
683                 return -1;
684         }
685
686         len = 0;
687         for (i = 0; i < valc; ++i) {
688                 char *val = valv[i];
689                 size_t val_len = strlen(val);
690
691                 if (value)
692                         value[len - 1] = ' ';
693                 oldval = value;
694                 value = realloc(value, len + val_len + 1);
695                 if (!value) {
696                         fprintf(stderr,
697                                 "Cannot malloc %zu bytes: %s\n",
698                                 len, strerror(errno));
699                         free(oldval);
700                         return -1;
701                 }
702
703                 memcpy(value + len, val, val_len);
704                 len += val_len;
705                 value[len++] = '\0';
706         }
707
708         fw_env_write(name, value);
709
710         free(value);
711
712         ret = fw_env_flush(opts);
713         fw_env_close(opts);
714
715         return ret;
716 }
717
718 /*
719  * Parse  a file  and configure the u-boot variables.
720  * The script file has a very simple format, as follows:
721  *
722  * Each line has a couple with name, value:
723  * <white spaces>variable_name<white spaces>variable_value
724  *
725  * Both variable_name and variable_value are interpreted as strings.
726  * Any character after <white spaces> and before ending \r\n is interpreted
727  * as variable's value (no comment allowed on these lines !)
728  *
729  * Comments are allowed if the first character in the line is #
730  *
731  * Returns -1 and sets errno error codes:
732  * 0      - OK
733  * -1     - Error
734  */
735 int fw_parse_script(char *fname, struct env_opts *opts)
736 {
737         FILE *fp;
738         char *line = NULL;
739         size_t linesize = 0;
740         char *name;
741         char *val;
742         int lineno = 0;
743         int len;
744         int ret = 0;
745
746         if (!opts)
747                 opts = &default_opts;
748
749         if (fw_env_open(opts)) {
750                 fprintf(stderr, "Error: environment not initialized\n");
751                 return -1;
752         }
753
754         if (strcmp(fname, "-") == 0)
755                 fp = stdin;
756         else {
757                 fp = fopen(fname, "r");
758                 if (fp == NULL) {
759                         fprintf(stderr, "I cannot open %s for reading\n",
760                                 fname);
761                         return -1;
762                 }
763         }
764
765         while ((len = getline(&line, &linesize, fp)) != -1) {
766                 lineno++;
767
768                 /*
769                  * Read a whole line from the file. If the line is not
770                  * terminated, reports an error and exit.
771                  */
772                 if (line[len - 1] != '\n') {
773                         fprintf(stderr,
774                                 "Line %d not correctly terminated\n",
775                                 lineno);
776                         ret = -1;
777                         break;
778                 }
779
780                 /* Drop ending line feed / carriage return */
781                 line[--len] = '\0';
782                 if (len && line[len - 1] == '\r')
783                         line[--len] = '\0';
784
785                 /* Skip comment or empty lines */
786                 if (len == 0 || line[0] == '#')
787                         continue;
788
789                 /*
790                  * Search for variable's name remove leading whitespaces
791                  */
792                 name = skip_blanks(line);
793                 if (!name)
794                         continue;
795
796                 /* The first white space is the end of variable name */
797                 val = skip_chars(name);
798                 len = strlen(name);
799                 if (val) {
800                         *val++ = '\0';
801                         if ((val - name) < len)
802                                 val = skip_blanks(val);
803                         else
804                                 val = NULL;
805                 }
806 #ifdef DEBUG
807                 fprintf(stderr, "Setting %s : %s\n",
808                         name, val ? val : " removed");
809 #endif
810
811                 if (env_flags_validate_type(name, val) < 0) {
812                         ret = -1;
813                         break;
814                 }
815
816                 /*
817                  * If there is an error setting a variable,
818                  * try to save the environment and returns an error
819                  */
820                 if (fw_env_write(name, val)) {
821                         fprintf(stderr,
822                                 "fw_env_write returns with error : %s\n",
823                                 strerror(errno));
824                         ret = -1;
825                         break;
826                 }
827
828         }
829         free(line);
830
831         /* Close file if not stdin */
832         if (strcmp(fname, "-") != 0)
833                 fclose(fp);
834
835         ret |= fw_env_flush(opts);
836
837         fw_env_close(opts);
838
839         return ret;
840 }
841
842 /**
843  * environment_end() - compute offset of first byte right after environment
844  * @dev - index of enviroment buffer
845  * Return:
846  *  device offset of first byte right after environment
847  */
848 off_t environment_end(int dev)
849 {
850         /* environment is block aligned */
851         return DEVOFFSET(dev) + ENVSECTORS(dev) * DEVESIZE(dev);
852 }
853
854 /*
855  * Test for bad block on NAND, just returns 0 on NOR, on NAND:
856  * 0    - block is good
857  * > 0  - block is bad
858  * < 0  - failed to test
859  */
860 static int flash_bad_block(int fd, uint8_t mtd_type, loff_t blockstart)
861 {
862         if (mtd_type == MTD_NANDFLASH) {
863                 int badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart);
864
865                 if (badblock < 0) {
866                         perror("Cannot read bad block mark");
867                         return badblock;
868                 }
869
870                 if (badblock) {
871 #ifdef DEBUG
872                         fprintf(stderr, "Bad block at 0x%llx, skipping\n",
873                                 (unsigned long long)blockstart);
874 #endif
875                         return badblock;
876                 }
877         }
878
879         return 0;
880 }
881
882 /*
883  * Read data from flash at an offset into a provided buffer. On NAND it skips
884  * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
885  * the DEVOFFSET (dev) block. On NOR the loop is only run once.
886  */
887 static int flash_read_buf(int dev, int fd, void *buf, size_t count,
888                           off_t offset)
889 {
890         size_t blocklen;        /* erase / write length - one block on NAND,
891                                    0 on NOR */
892         size_t processed = 0;   /* progress counter */
893         size_t readlen = count; /* current read length */
894         off_t block_seek;       /* offset inside the current block to the start
895                                    of the data */
896         loff_t blockstart;      /* running start of the current block -
897                                    MEMGETBADBLOCK needs 64 bits */
898         int rc;
899
900         blockstart = (offset / DEVESIZE(dev)) * DEVESIZE(dev);
901
902         /* Offset inside a block */
903         block_seek = offset - blockstart;
904
905         if (DEVTYPE(dev) == MTD_NANDFLASH) {
906                 /*
907                  * NAND: calculate which blocks we are reading. We have
908                  * to read one block at a time to skip bad blocks.
909                  */
910                 blocklen = DEVESIZE(dev);
911
912                 /* Limit to one block for the first read */
913                 if (readlen > blocklen - block_seek)
914                         readlen = blocklen - block_seek;
915         } else {
916                 blocklen = 0;
917         }
918
919         /* This only runs once on NOR flash */
920         while (processed < count) {
921                 rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
922                 if (rc < 0)     /* block test failed */
923                         return -1;
924
925                 if (blockstart + block_seek + readlen > environment_end(dev)) {
926                         /* End of range is reached */
927                         fprintf(stderr, "Too few good blocks within range\n");
928                         return -1;
929                 }
930
931                 if (rc) {       /* block is bad */
932                         blockstart += blocklen;
933                         continue;
934                 }
935
936                 /*
937                  * If a block is bad, we retry in the next block at the same
938                  * offset - see env/nand.c::writeenv()
939                  */
940                 lseek(fd, blockstart + block_seek, SEEK_SET);
941
942                 rc = read(fd, buf + processed, readlen);
943                 if (rc != readlen) {
944                         fprintf(stderr, "Read error on %s: %s\n",
945                                 DEVNAME(dev), strerror(errno));
946                         return -1;
947                 }
948 #ifdef DEBUG
949                 fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
950                         rc, (unsigned long long)blockstart + block_seek,
951                         DEVNAME(dev));
952 #endif
953                 processed += readlen;
954                 readlen = min(blocklen, count - processed);
955                 block_seek = 0;
956                 blockstart += blocklen;
957         }
958
959         return processed;
960 }
961
962 /*
963  * Write count bytes from begin of environment, but stay within
964  * ENVSECTORS(dev) sectors of
965  * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
966  * erase and write the whole data at once.
967  */
968 static int flash_write_buf(int dev, int fd, void *buf, size_t count)
969 {
970         void *data;
971         struct erase_info_user erase;
972         size_t blocklen;        /* length of NAND block / NOR erase sector */
973         size_t erase_len;       /* whole area that can be erased - may include
974                                    bad blocks */
975         size_t erasesize;       /* erase / write length - one block on NAND,
976                                    whole area on NOR */
977         size_t processed = 0;   /* progress counter */
978         size_t write_total;     /* total size to actually write - excluding
979                                    bad blocks */
980         off_t erase_offset;     /* offset to the first erase block (aligned)
981                                    below offset */
982         off_t block_seek;       /* offset inside the erase block to the start
983                                    of the data */
984         loff_t blockstart;      /* running start of the current block -
985                                    MEMGETBADBLOCK needs 64 bits */
986         int rc;
987
988         /*
989          * For mtd devices only offset and size of the environment do matter
990          */
991         if (DEVTYPE(dev) == MTD_ABSENT) {
992                 blocklen = count;
993                 erase_len = blocklen;
994                 blockstart = DEVOFFSET(dev);
995                 block_seek = 0;
996                 write_total = blocklen;
997         } else {
998                 blocklen = DEVESIZE(dev);
999
1000                 erase_offset = DEVOFFSET(dev);
1001
1002                 /* Maximum area we may use */
1003                 erase_len = environment_end(dev) - erase_offset;
1004
1005                 blockstart = erase_offset;
1006
1007                 /* Offset inside a block */
1008                 block_seek = DEVOFFSET(dev) - erase_offset;
1009
1010                 /*
1011                  * Data size we actually write: from the start of the block
1012                  * to the start of the data, then count bytes of data, and
1013                  * to the end of the block
1014                  */
1015                 write_total = ((block_seek + count + blocklen - 1) /
1016                                blocklen) * blocklen;
1017         }
1018
1019         /*
1020          * Support data anywhere within erase sectors: read out the complete
1021          * area to be erased, replace the environment image, write the whole
1022          * block back again.
1023          */
1024         if (write_total > count) {
1025                 data = malloc(erase_len);
1026                 if (!data) {
1027                         fprintf(stderr,
1028                                 "Cannot malloc %zu bytes: %s\n",
1029                                 erase_len, strerror(errno));
1030                         return -1;
1031                 }
1032
1033                 rc = flash_read_buf(dev, fd, data, write_total, erase_offset);
1034                 if (write_total != rc)
1035                         return -1;
1036
1037 #ifdef DEBUG
1038                 fprintf(stderr, "Preserving data ");
1039                 if (block_seek != 0)
1040                         fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1);
1041                 if (block_seek + count != write_total) {
1042                         if (block_seek != 0)
1043                                 fprintf(stderr, " and ");
1044                         fprintf(stderr, "0x%lx - 0x%lx",
1045                                 (unsigned long)block_seek + count,
1046                                 (unsigned long)write_total - 1);
1047                 }
1048                 fprintf(stderr, "\n");
1049 #endif
1050                 /* Overwrite the old environment */
1051                 memcpy(data + block_seek, buf, count);
1052         } else {
1053                 /*
1054                  * We get here, iff offset is block-aligned and count is a
1055                  * multiple of blocklen - see write_total calculation above
1056                  */
1057                 data = buf;
1058         }
1059
1060         if (DEVTYPE(dev) == MTD_NANDFLASH) {
1061                 /*
1062                  * NAND: calculate which blocks we are writing. We have
1063                  * to write one block at a time to skip bad blocks.
1064                  */
1065                 erasesize = blocklen;
1066         } else {
1067                 erasesize = erase_len;
1068         }
1069
1070         erase.length = erasesize;
1071
1072         /* This only runs once on NOR flash and SPI-dataflash */
1073         while (processed < write_total) {
1074                 rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
1075                 if (rc < 0)     /* block test failed */
1076                         return rc;
1077
1078                 if (blockstart + erasesize > environment_end(dev)) {
1079                         fprintf(stderr, "End of range reached, aborting\n");
1080                         return -1;
1081                 }
1082
1083                 if (rc) {       /* block is bad */
1084                         blockstart += blocklen;
1085                         continue;
1086                 }
1087
1088                 if (DEVTYPE(dev) != MTD_ABSENT) {
1089                         erase.start = blockstart;
1090                         ioctl(fd, MEMUNLOCK, &erase);
1091                         /* These do not need an explicit erase cycle */
1092                         if (DEVTYPE(dev) != MTD_DATAFLASH)
1093                                 if (ioctl(fd, MEMERASE, &erase) != 0) {
1094                                         fprintf(stderr,
1095                                                 "MTD erase error on %s: %s\n",
1096                                                 DEVNAME(dev), strerror(errno));
1097                                         return -1;
1098                                 }
1099                 }
1100
1101                 if (lseek(fd, blockstart, SEEK_SET) == -1) {
1102                         fprintf(stderr,
1103                                 "Seek error on %s: %s\n",
1104                                 DEVNAME(dev), strerror(errno));
1105                         return -1;
1106                 }
1107 #ifdef DEBUG
1108                 fprintf(stderr, "Write 0x%llx bytes at 0x%llx\n",
1109                         (unsigned long long)erasesize,
1110                         (unsigned long long)blockstart);
1111 #endif
1112                 if (write(fd, data + processed, erasesize) != erasesize) {
1113                         fprintf(stderr, "Write error on %s: %s\n",
1114                                 DEVNAME(dev), strerror(errno));
1115                         return -1;
1116                 }
1117
1118                 if (DEVTYPE(dev) != MTD_ABSENT)
1119                         ioctl(fd, MEMLOCK, &erase);
1120
1121                 processed += erasesize;
1122                 block_seek = 0;
1123                 blockstart += erasesize;
1124         }
1125
1126         if (write_total > count)
1127                 free(data);
1128
1129         return processed;
1130 }
1131
1132 /*
1133  * Set obsolete flag at offset - NOR flash only
1134  */
1135 static int flash_flag_obsolete(int dev, int fd, off_t offset)
1136 {
1137         int rc;
1138         struct erase_info_user erase;
1139         char tmp = ENV_REDUND_OBSOLETE;
1140
1141         erase.start = DEVOFFSET(dev);
1142         erase.length = DEVESIZE(dev);
1143         /* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */
1144         rc = lseek(fd, offset, SEEK_SET);
1145         if (rc < 0) {
1146                 fprintf(stderr, "Cannot seek to set the flag on %s\n",
1147                         DEVNAME(dev));
1148                 return rc;
1149         }
1150         ioctl(fd, MEMUNLOCK, &erase);
1151         rc = write(fd, &tmp, sizeof(tmp));
1152         ioctl(fd, MEMLOCK, &erase);
1153         if (rc < 0)
1154                 perror("Could not set obsolete flag");
1155
1156         return rc;
1157 }
1158
1159 static int flash_write(int fd_current, int fd_target, int dev_target)
1160 {
1161         int rc;
1162
1163         switch (environment.flag_scheme) {
1164         case FLAG_NONE:
1165                 break;
1166         case FLAG_INCREMENTAL:
1167                 (*environment.flags)++;
1168                 break;
1169         case FLAG_BOOLEAN:
1170                 *environment.flags = ENV_REDUND_ACTIVE;
1171                 break;
1172         default:
1173                 fprintf(stderr, "Unimplemented flash scheme %u\n",
1174                         environment.flag_scheme);
1175                 return -1;
1176         }
1177
1178 #ifdef DEBUG
1179         fprintf(stderr, "Writing new environment at 0x%llx on %s\n",
1180                 DEVOFFSET(dev_target), DEVNAME(dev_target));
1181 #endif
1182
1183         if (IS_UBI(dev_target)) {
1184                 if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0)
1185                         return 0;
1186                 return ubi_write(fd_target, environment.image, CUR_ENVSIZE);
1187         }
1188
1189         rc = flash_write_buf(dev_target, fd_target, environment.image,
1190                              CUR_ENVSIZE);
1191         if (rc < 0)
1192                 return rc;
1193
1194         if (environment.flag_scheme == FLAG_BOOLEAN) {
1195                 /* Have to set obsolete flag */
1196                 off_t offset = DEVOFFSET(dev_current) +
1197                     offsetof(struct env_image_redundant, flags);
1198 #ifdef DEBUG
1199                 fprintf(stderr,
1200                         "Setting obsolete flag in environment at 0x%llx on %s\n",
1201                         DEVOFFSET(dev_current), DEVNAME(dev_current));
1202 #endif
1203                 flash_flag_obsolete(dev_current, fd_current, offset);
1204         }
1205
1206         return 0;
1207 }
1208
1209 static int flash_read(int fd)
1210 {
1211         int rc;
1212
1213         if (IS_UBI(dev_current)) {
1214                 DEVTYPE(dev_current) = MTD_ABSENT;
1215
1216                 return ubi_read(fd, environment.image, CUR_ENVSIZE);
1217         }
1218
1219         rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
1220                             DEVOFFSET(dev_current));
1221         if (rc != CUR_ENVSIZE)
1222                 return -1;
1223
1224         return 0;
1225 }
1226
1227 static int flash_open_tempfile(const char **dname, const char **target_temp)
1228 {
1229         char *dup_name = strdup(DEVNAME(dev_current));
1230         char *temp_name = NULL;
1231         int rc = -1;
1232
1233         if (!dup_name)
1234                 return -1;
1235
1236         *dname = dirname(dup_name);
1237         if (!*dname)
1238                 goto err;
1239
1240         rc = asprintf(&temp_name, "%s/XXXXXX", *dname);
1241         if (rc == -1)
1242                 goto err;
1243
1244         rc = mkstemp(temp_name);
1245         if (rc == -1) {
1246                 /* fall back to in place write */
1247                 fprintf(stderr,
1248                         "Can't create %s: %s\n", temp_name, strerror(errno));
1249                 free(temp_name);
1250         } else {
1251                 *target_temp = temp_name;
1252                 /* deliberately leak dup_name as dname /might/ point into
1253                  * it and we need it for our caller
1254                  */
1255                 dup_name = NULL;
1256         }
1257
1258 err:
1259         if (dup_name)
1260                 free(dup_name);
1261
1262         return rc;
1263 }
1264
1265 static int flash_io_write(int fd_current)
1266 {
1267         int fd_target = -1, rc, dev_target;
1268         const char *dname, *target_temp = NULL;
1269
1270         if (have_redund_env) {
1271                 /* switch to next partition for writing */
1272                 dev_target = !dev_current;
1273                 /* dev_target: fd_target, erase_target */
1274                 fd_target = open(DEVNAME(dev_target), O_RDWR);
1275                 if (fd_target < 0) {
1276                         fprintf(stderr,
1277                                 "Can't open %s: %s\n",
1278                                 DEVNAME(dev_target), strerror(errno));
1279                         rc = -1;
1280                         goto exit;
1281                 }
1282         } else {
1283                 struct stat sb;
1284
1285                 if (fstat(fd_current, &sb) == 0 && S_ISREG(sb.st_mode)) {
1286                         /* if any part of flash_open_tempfile() fails we fall
1287                          * back to in-place writes
1288                          */
1289                         fd_target = flash_open_tempfile(&dname, &target_temp);
1290                 }
1291                 dev_target = dev_current;
1292                 if (fd_target == -1)
1293                         fd_target = fd_current;
1294         }
1295
1296         rc = flash_write(fd_current, fd_target, dev_target);
1297
1298         if (fsync(fd_current) && !(errno == EINVAL || errno == EROFS)) {
1299                 fprintf(stderr,
1300                         "fsync failed on %s: %s\n",
1301                         DEVNAME(dev_current), strerror(errno));
1302         }
1303
1304         if (fd_current != fd_target) {
1305                 if (fsync(fd_target) &&
1306                     !(errno == EINVAL || errno == EROFS)) {
1307                         fprintf(stderr,
1308                                 "fsync failed on %s: %s\n",
1309                                 DEVNAME(dev_current), strerror(errno));
1310                 }
1311
1312                 if (close(fd_target)) {
1313                         fprintf(stderr,
1314                                 "I/O error on %s: %s\n",
1315                                 DEVNAME(dev_target), strerror(errno));
1316                         rc = -1;
1317                 }
1318
1319                 if (rc >= 0 && target_temp) {
1320                         int dir_fd;
1321
1322                         dir_fd = open(dname, O_DIRECTORY | O_RDONLY);
1323                         if (dir_fd == -1)
1324                                 fprintf(stderr,
1325                                         "Can't open %s: %s\n",
1326                                         dname, strerror(errno));
1327
1328                         if (rename(target_temp, DEVNAME(dev_target))) {
1329                                 fprintf(stderr,
1330                                         "rename failed %s => %s: %s\n",
1331                                         target_temp, DEVNAME(dev_target),
1332                                         strerror(errno));
1333                                 rc = -1;
1334                         }
1335
1336                         if (dir_fd != -1 && fsync(dir_fd))
1337                                 fprintf(stderr,
1338                                         "fsync failed on %s: %s\n",
1339                                         dname, strerror(errno));
1340
1341                         if (dir_fd != -1 && close(dir_fd))
1342                                 fprintf(stderr,
1343                                         "I/O error on %s: %s\n",
1344                                         dname, strerror(errno));
1345                 }
1346         }
1347  exit:
1348         return rc;
1349 }
1350
1351 static int flash_io(int mode)
1352 {
1353         int fd_current, rc;
1354
1355         /* dev_current: fd_current, erase_current */
1356         fd_current = open(DEVNAME(dev_current), mode);
1357         if (fd_current < 0) {
1358                 fprintf(stderr,
1359                         "Can't open %s: %s\n",
1360                         DEVNAME(dev_current), strerror(errno));
1361                 return -1;
1362         }
1363
1364         if (mode == O_RDWR) {
1365                 rc = flash_io_write(fd_current);
1366         } else {
1367                 rc = flash_read(fd_current);
1368         }
1369
1370         if (close(fd_current)) {
1371                 fprintf(stderr,
1372                         "I/O error on %s: %s\n",
1373                         DEVNAME(dev_current), strerror(errno));
1374                 return -1;
1375         }
1376
1377         return rc;
1378 }
1379
1380 /*
1381  * Prevent confusion if running from erased flash memory
1382  */
1383 int fw_env_open(struct env_opts *opts)
1384 {
1385         int crc0, crc0_ok;
1386         unsigned char flag0;
1387         void *addr0 = NULL;
1388
1389         int crc1, crc1_ok;
1390         unsigned char flag1;
1391         void *addr1 = NULL;
1392
1393         int ret;
1394
1395         struct env_image_single *single;
1396         struct env_image_redundant *redundant;
1397
1398         if (!opts)
1399                 opts = &default_opts;
1400
1401         if (parse_config(opts)) /* should fill envdevices */
1402                 return -EINVAL;
1403
1404         addr0 = calloc(1, CUR_ENVSIZE);
1405         if (addr0 == NULL) {
1406                 fprintf(stderr,
1407                         "Not enough memory for environment (%ld bytes)\n",
1408                         CUR_ENVSIZE);
1409                 ret = -ENOMEM;
1410                 goto open_cleanup;
1411         }
1412
1413         /* read environment from FLASH to local buffer */
1414         environment.image = addr0;
1415
1416         if (have_redund_env) {
1417                 redundant = addr0;
1418                 environment.crc = &redundant->crc;
1419                 environment.flags = &redundant->flags;
1420                 environment.data = redundant->data;
1421         } else {
1422                 single = addr0;
1423                 environment.crc = &single->crc;
1424                 environment.flags = NULL;
1425                 environment.data = single->data;
1426         }
1427
1428         dev_current = 0;
1429         if (flash_io(O_RDONLY)) {
1430                 ret = -EIO;
1431                 goto open_cleanup;
1432         }
1433
1434         crc0 = crc32(0, (uint8_t *)environment.data, ENV_SIZE);
1435
1436         crc0_ok = (crc0 == *environment.crc);
1437         if (!have_redund_env) {
1438                 if (!crc0_ok) {
1439                         fprintf(stderr,
1440                                 "Warning: Bad CRC, using default environment\n");
1441                         memcpy(environment.data, default_environment,
1442                                sizeof(default_environment));
1443                 }
1444         } else {
1445                 flag0 = *environment.flags;
1446
1447                 dev_current = 1;
1448                 addr1 = calloc(1, CUR_ENVSIZE);
1449                 if (addr1 == NULL) {
1450                         fprintf(stderr,
1451                                 "Not enough memory for environment (%ld bytes)\n",
1452                                 CUR_ENVSIZE);
1453                         ret = -ENOMEM;
1454                         goto open_cleanup;
1455                 }
1456                 redundant = addr1;
1457
1458                 /*
1459                  * have to set environment.image for flash_read(), careful -
1460                  * other pointers in environment still point inside addr0
1461                  */
1462                 environment.image = addr1;
1463                 if (flash_io(O_RDONLY)) {
1464                         ret = -EIO;
1465                         goto open_cleanup;
1466                 }
1467
1468                 /* Check flag scheme compatibility */
1469                 if (DEVTYPE(dev_current) == MTD_NORFLASH &&
1470                     DEVTYPE(!dev_current) == MTD_NORFLASH) {
1471                         environment.flag_scheme = FLAG_BOOLEAN;
1472                 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
1473                            DEVTYPE(!dev_current) == MTD_NANDFLASH) {
1474                         environment.flag_scheme = FLAG_INCREMENTAL;
1475                 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
1476                            DEVTYPE(!dev_current) == MTD_DATAFLASH) {
1477                         environment.flag_scheme = FLAG_BOOLEAN;
1478                 } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
1479                            DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
1480                         environment.flag_scheme = FLAG_INCREMENTAL;
1481                 } else if (DEVTYPE(dev_current) == MTD_ABSENT &&
1482                            DEVTYPE(!dev_current) == MTD_ABSENT &&
1483                            IS_UBI(dev_current) == IS_UBI(!dev_current)) {
1484                         environment.flag_scheme = FLAG_INCREMENTAL;
1485                 } else {
1486                         fprintf(stderr, "Incompatible flash types!\n");
1487                         ret = -EINVAL;
1488                         goto open_cleanup;
1489                 }
1490
1491                 crc1 = crc32(0, (uint8_t *)redundant->data, ENV_SIZE);
1492
1493                 crc1_ok = (crc1 == redundant->crc);
1494                 flag1 = redundant->flags;
1495
1496                 if (crc0_ok && !crc1_ok) {
1497                         dev_current = 0;
1498                 } else if (!crc0_ok && crc1_ok) {
1499                         dev_current = 1;
1500                 } else if (!crc0_ok && !crc1_ok) {
1501                         fprintf(stderr,
1502                                 "Warning: Bad CRC, using default environment\n");
1503                         memcpy(environment.data, default_environment,
1504                                sizeof(default_environment));
1505                         dev_current = 0;
1506                 } else {
1507                         switch (environment.flag_scheme) {
1508                         case FLAG_BOOLEAN:
1509                                 if (flag0 == ENV_REDUND_ACTIVE &&
1510                                     flag1 == ENV_REDUND_OBSOLETE) {
1511                                         dev_current = 0;
1512                                 } else if (flag0 == ENV_REDUND_OBSOLETE &&
1513                                            flag1 == ENV_REDUND_ACTIVE) {
1514                                         dev_current = 1;
1515                                 } else if (flag0 == flag1) {
1516                                         dev_current = 0;
1517                                 } else if (flag0 == 0xFF) {
1518                                         dev_current = 0;
1519                                 } else if (flag1 == 0xFF) {
1520                                         dev_current = 1;
1521                                 } else {
1522                                         dev_current = 0;
1523                                 }
1524                                 break;
1525                         case FLAG_INCREMENTAL:
1526                                 if (flag0 == 255 && flag1 == 0)
1527                                         dev_current = 1;
1528                                 else if ((flag1 == 255 && flag0 == 0) ||
1529                                          flag0 >= flag1)
1530                                         dev_current = 0;
1531                                 else    /* flag1 > flag0 */
1532                                         dev_current = 1;
1533                                 break;
1534                         default:
1535                                 fprintf(stderr, "Unknown flag scheme %u\n",
1536                                         environment.flag_scheme);
1537                                 return -1;
1538                         }
1539                 }
1540
1541                 /*
1542                  * If we are reading, we don't need the flag and the CRC any
1543                  * more, if we are writing, we will re-calculate CRC and update
1544                  * flags before writing out
1545                  */
1546                 if (dev_current) {
1547                         environment.image = addr1;
1548                         environment.crc = &redundant->crc;
1549                         environment.flags = &redundant->flags;
1550                         environment.data = redundant->data;
1551                         free(addr0);
1552                 } else {
1553                         environment.image = addr0;
1554                         /* Other pointers are already set */
1555                         free(addr1);
1556                 }
1557 #ifdef DEBUG
1558                 fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
1559 #endif
1560         }
1561         return 0;
1562
1563  open_cleanup:
1564         if (addr0)
1565                 free(addr0);
1566
1567         if (addr1)
1568                 free(addr1);
1569
1570         return ret;
1571 }
1572
1573 /*
1574  * Simply free allocated buffer with environment
1575  */
1576 int fw_env_close(struct env_opts *opts)
1577 {
1578         if (environment.image)
1579                 free(environment.image);
1580
1581         environment.image = NULL;
1582
1583         return 0;
1584 }
1585
1586 static int check_device_config(int dev)
1587 {
1588         struct stat st;
1589         int32_t lnum = 0;
1590         int fd, rc = 0;
1591
1592         /* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */
1593         ubi_check_dev(dev);
1594
1595         fd = open(DEVNAME(dev), O_RDONLY);
1596         if (fd < 0) {
1597                 fprintf(stderr,
1598                         "Cannot open %s: %s\n", DEVNAME(dev), strerror(errno));
1599                 return -1;
1600         }
1601
1602         rc = fstat(fd, &st);
1603         if (rc < 0) {
1604                 fprintf(stderr, "Cannot stat the file %s\n", DEVNAME(dev));
1605                 goto err;
1606         }
1607
1608         if (IS_UBI(dev)) {
1609                 rc = ioctl(fd, UBI_IOCEBISMAP, &lnum);
1610                 if (rc < 0) {
1611                         fprintf(stderr, "Cannot get UBI information for %s\n",
1612                                 DEVNAME(dev));
1613                         goto err;
1614                 }
1615         } else if (S_ISCHR(st.st_mode)) {
1616                 struct mtd_info_user mtdinfo;
1617                 rc = ioctl(fd, MEMGETINFO, &mtdinfo);
1618                 if (rc < 0) {
1619                         fprintf(stderr, "Cannot get MTD information for %s\n",
1620                                 DEVNAME(dev));
1621                         goto err;
1622                 }
1623                 if (mtdinfo.type != MTD_NORFLASH &&
1624                     mtdinfo.type != MTD_NANDFLASH &&
1625                     mtdinfo.type != MTD_DATAFLASH &&
1626                     mtdinfo.type != MTD_UBIVOLUME) {
1627                         fprintf(stderr, "Unsupported flash type %u on %s\n",
1628                                 mtdinfo.type, DEVNAME(dev));
1629                         goto err;
1630                 }
1631                 DEVTYPE(dev) = mtdinfo.type;
1632                 if (DEVESIZE(dev) == 0)
1633                         /* Assume the erase size is the same as the env-size */
1634                         DEVESIZE(dev) = ENVSIZE(dev);
1635         } else {
1636                 uint64_t size;
1637                 DEVTYPE(dev) = MTD_ABSENT;
1638                 if (DEVESIZE(dev) == 0)
1639                         /* Assume the erase size to be 512 bytes */
1640                         DEVESIZE(dev) = 0x200;
1641
1642                 /*
1643                  * Check for negative offsets, treat it as backwards offset
1644                  * from the end of the block device
1645                  */
1646                 if (DEVOFFSET(dev) < 0) {
1647                         rc = ioctl(fd, BLKGETSIZE64, &size);
1648                         if (rc < 0) {
1649                                 fprintf(stderr,
1650                                         "Could not get block device size on %s\n",
1651                                         DEVNAME(dev));
1652                                 goto err;
1653                         }
1654
1655                         DEVOFFSET(dev) = DEVOFFSET(dev) + size;
1656 #ifdef DEBUG
1657                         fprintf(stderr,
1658                                 "Calculated device offset 0x%llx on %s\n",
1659                                 DEVOFFSET(dev), DEVNAME(dev));
1660 #endif
1661                 }
1662         }
1663
1664         if (ENVSECTORS(dev) == 0)
1665                 /* Assume enough sectors to cover the environment */
1666                 ENVSECTORS(dev) = DIV_ROUND_UP(ENVSIZE(dev), DEVESIZE(dev));
1667
1668         if (DEVOFFSET(dev) % DEVESIZE(dev) != 0) {
1669                 fprintf(stderr,
1670                         "Environment does not start on (erase) block boundary\n");
1671                 errno = EINVAL;
1672                 return -1;
1673         }
1674
1675         if (ENVSIZE(dev) > ENVSECTORS(dev) * DEVESIZE(dev)) {
1676                 fprintf(stderr,
1677                         "Environment does not fit into available sectors\n");
1678                 errno = EINVAL;
1679                 return -1;
1680         }
1681
1682  err:
1683         close(fd);
1684         return rc;
1685 }
1686
1687 static int parse_config(struct env_opts *opts)
1688 {
1689         int rc;
1690
1691         if (!opts)
1692                 opts = &default_opts;
1693
1694 #if defined(CONFIG_FILE)
1695         /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
1696         if (get_config(opts->config_file)) {
1697                 fprintf(stderr, "Cannot parse config file '%s': %m\n",
1698                         opts->config_file);
1699                 return -1;
1700         }
1701 #else
1702         DEVNAME(0) = DEVICE1_NAME;
1703         DEVOFFSET(0) = DEVICE1_OFFSET;
1704         ENVSIZE(0) = ENV1_SIZE;
1705
1706         /* Set defaults for DEVESIZE, ENVSECTORS later once we
1707          * know DEVTYPE
1708          */
1709 #ifdef DEVICE1_ESIZE
1710         DEVESIZE(0) = DEVICE1_ESIZE;
1711 #endif
1712 #ifdef DEVICE1_ENVSECTORS
1713         ENVSECTORS(0) = DEVICE1_ENVSECTORS;
1714 #endif
1715
1716 #ifdef HAVE_REDUND
1717         DEVNAME(1) = DEVICE2_NAME;
1718         DEVOFFSET(1) = DEVICE2_OFFSET;
1719         ENVSIZE(1) = ENV2_SIZE;
1720
1721         /* Set defaults for DEVESIZE, ENVSECTORS later once we
1722          * know DEVTYPE
1723          */
1724 #ifdef DEVICE2_ESIZE
1725         DEVESIZE(1) = DEVICE2_ESIZE;
1726 #endif
1727 #ifdef DEVICE2_ENVSECTORS
1728         ENVSECTORS(1) = DEVICE2_ENVSECTORS;
1729 #endif
1730         have_redund_env = 1;
1731 #endif
1732 #endif
1733         rc = check_device_config(0);
1734         if (rc < 0)
1735                 return rc;
1736
1737         if (have_redund_env) {
1738                 rc = check_device_config(1);
1739                 if (rc < 0)
1740                         return rc;
1741
1742                 if (ENVSIZE(0) != ENVSIZE(1)) {
1743                         fprintf(stderr,
1744                                 "Redundant environments have unequal size\n");
1745                         return -1;
1746                 }
1747         }
1748
1749         usable_envsize = CUR_ENVSIZE - sizeof(uint32_t);
1750         if (have_redund_env)
1751                 usable_envsize -= sizeof(char);
1752
1753         return 0;
1754 }
1755
1756 #if defined(CONFIG_FILE)
1757 static int get_config(char *fname)
1758 {
1759         FILE *fp;
1760         int i = 0;
1761         int rc;
1762         char *line = NULL;
1763         size_t linesize = 0;
1764         char *devname;
1765
1766         fp = fopen(fname, "r");
1767         if (fp == NULL)
1768                 return -1;
1769
1770         while (i < 2 && getline(&line, &linesize, fp) != -1) {
1771                 /* Skip comment strings */
1772                 if (line[0] == '#')
1773                         continue;
1774
1775                 rc = sscanf(line, "%ms %lli %lx %lx %lx",
1776                             &devname,
1777                             &DEVOFFSET(i),
1778                             &ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i));
1779
1780                 if (rc < 3)
1781                         continue;
1782
1783                 DEVNAME(i) = devname;
1784
1785                 /* Set defaults for DEVESIZE, ENVSECTORS later once we
1786                  * know DEVTYPE
1787                  */
1788
1789                 i++;
1790         }
1791         free(line);
1792         fclose(fp);
1793
1794         have_redund_env = i - 1;
1795         if (!i) {               /* No valid entries found */
1796                 errno = EINVAL;
1797                 return -1;
1798         } else
1799                 return 0;
1800 }
1801 #endif