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