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