fw_env.c 38.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
3
 * (C) Copyright 2000-2010
4 5
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
G
Guennadi Liakhovetski 已提交
6 7
 * (C) Copyright 2008
 * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de.
8 9
 */

J
Jörg Krause 已提交
10 11
#define _GNU_SOURCE

P
Peter Robinson 已提交
12
#include <compiler.h>
S
Simon Glass 已提交
13
#include <env.h>
14
#include <errno.h>
15
#include <env_flags.h>
16
#include <fcntl.h>
17
#include <libgen.h>
S
Stefan Agner 已提交
18
#include <linux/fs.h>
19
#include <linux/stringify.h>
20
#include <ctype.h>
21 22 23 24 25 26 27
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
28
#include <u-boot/crc.h>
29
#include <unistd.h>
30
#include <dirent.h>
31

32
#ifdef MTD_OLD
33
# include <stdint.h>
34 35
# include <linux/mtd/mtd.h>
#else
36
# define  __user	/* nothing */
37 38 39
# include <mtd/mtd-user.h>
#endif

40 41
#include <mtd/ubi-user.h>

42
#include "fw_env_private.h"
43
#include "fw_env.h"
44

45 46 47 48 49 50
struct env_opts default_opts = {
#ifdef CONFIG_FILE
	.config_file = CONFIG_FILE
#endif
};

51 52
#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))

G
Guennadi Liakhovetski 已提交
53 54 55 56 57 58 59
#define min(x, y) ({				\
	typeof(x) _min1 = (x);			\
	typeof(y) _min2 = (y);			\
	(void) (&_min1 == &_min2);		\
	_min1 < _min2 ? _min1 : _min2; })

struct envdev_s {
60
	const char *devname;		/* Device name */
S
Stefan Agner 已提交
61
	long long devoff;		/* Device offset */
W
wdenk 已提交
62 63
	ulong env_size;			/* environment size */
	ulong erase_size;		/* device erase size */
G
Guennadi Liakhovetski 已提交
64 65
	ulong env_sectors;		/* number of environment sectors */
	uint8_t mtd_type;		/* type of the MTD device */
66
	int is_ubi;			/* set if we use UBI volume */
G
Guennadi Liakhovetski 已提交
67
};
68

A
Alex Kiernan 已提交
69
static struct envdev_s envdevices[2] = {
G
Guennadi Liakhovetski 已提交
70 71 72 73 74 75
	{
		.mtd_type = MTD_ABSENT,
	}, {
		.mtd_type = MTD_ABSENT,
	},
};
A
Alex Kiernan 已提交
76

G
Guennadi Liakhovetski 已提交
77
static int dev_current;
78 79

#define DEVNAME(i)    envdevices[(i)].devname
80
#define DEVOFFSET(i)  envdevices[(i)].devoff
81 82
#define ENVSIZE(i)    envdevices[(i)].env_size
#define DEVESIZE(i)   envdevices[(i)].erase_size
G
Guennadi Liakhovetski 已提交
83 84
#define ENVSECTORS(i) envdevices[(i)].env_sectors
#define DEVTYPE(i)    envdevices[(i)].mtd_type
85
#define IS_UBI(i)     envdevices[(i)].is_ubi
86

87
#define CUR_ENVSIZE ENVSIZE(dev_current)
88

89 90
static unsigned long usable_envsize;
#define ENV_SIZE      usable_envsize
91

G
Guennadi Liakhovetski 已提交
92
struct env_image_single {
A
Alex Kiernan 已提交
93 94
	uint32_t crc;		/* CRC32 over data bytes    */
	char data[];
G
Guennadi Liakhovetski 已提交
95
};
96

G
Guennadi Liakhovetski 已提交
97
struct env_image_redundant {
A
Alex Kiernan 已提交
98 99 100
	uint32_t crc;		/* CRC32 over data bytes    */
	unsigned char flags;	/* active or obsolete */
	char data[];
G
Guennadi Liakhovetski 已提交
101 102 103 104 105 106 107 108 109
};

enum flag_scheme {
	FLAG_NONE,
	FLAG_BOOLEAN,
	FLAG_INCREMENTAL,
};

struct environment {
A
Alex Kiernan 已提交
110 111 112 113 114
	void *image;
	uint32_t *crc;
	unsigned char *flags;
	char *data;
	enum flag_scheme flag_scheme;
115
	int dirty;
G
Guennadi Liakhovetski 已提交
116 117 118 119 120
};

static struct environment environment = {
	.flag_scheme = FLAG_NONE,
};
121

122
static int have_redund_env;
123

124 125
#define DEFAULT_ENV_INSTANCE_STATIC
#include <env_default.h>
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
#define UBI_DEV_START "/dev/ubi"
#define UBI_SYSFS "/sys/class/ubi"
#define UBI_VOL_NAME_PATT "ubi%d_%d"

static int is_ubi_devname(const char *devname)
{
	return !strncmp(devname, UBI_DEV_START, sizeof(UBI_DEV_START) - 1);
}

static int ubi_check_volume_sysfs_name(const char *volume_sysfs_name,
				       const char *volname)
{
	char path[256];
	FILE *file;
	char *name;
	int ret;

	strcpy(path, UBI_SYSFS "/");
	strcat(path, volume_sysfs_name);
	strcat(path, "/name");

	file = fopen(path, "r");
	if (!file)
		return -1;

	ret = fscanf(file, "%ms", &name);
	fclose(file);
	if (ret <= 0 || !name) {
		fprintf(stderr,
			"Failed to read from file %s, ret = %d, name = %s\n",
			path, ret, name);
		return -1;
	}

	if (!strcmp(name, volname)) {
		free(name);
		return 0;
	}
	free(name);

	return -1;
}

static int ubi_get_volnum_by_name(int devnum, const char *volname)
{
	DIR *sysfs_ubi;
	struct dirent *dirent;
	int ret;
	int tmp_devnum;
	int volnum;

	sysfs_ubi = opendir(UBI_SYSFS);
	if (!sysfs_ubi)
		return -1;

#ifdef DEBUG
	fprintf(stderr, "Looking for volume name \"%s\"\n", volname);
#endif

	while (1) {
		dirent = readdir(sysfs_ubi);
		if (!dirent)
			return -1;

		ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT,
			     &tmp_devnum, &volnum);
		if (ret == 2 && devnum == tmp_devnum) {
			if (ubi_check_volume_sysfs_name(dirent->d_name,
							volname) == 0)
				return volnum;
		}
	}

	return -1;
}

static int ubi_get_devnum_by_devname(const char *devname)
{
	int devnum;
	int ret;

	ret = sscanf(devname + sizeof(UBI_DEV_START) - 1, "%d", &devnum);
	if (ret != 1)
		return -1;

	return devnum;
}

static const char *ubi_get_volume_devname(const char *devname,
					  const char *volname)
{
	char *volume_devname;
	int volnum;
	int devnum;
	int ret;

	devnum = ubi_get_devnum_by_devname(devname);
	if (devnum < 0)
		return NULL;

	volnum = ubi_get_volnum_by_name(devnum, volname);
	if (volnum < 0)
		return NULL;

	ret = asprintf(&volume_devname, "%s_%d", devname, volnum);
	if (ret < 0)
		return NULL;

#ifdef DEBUG
	fprintf(stderr, "Found ubi volume \"%s:%s\" -> %s\n",
		devname, volname, volume_devname);
#endif

	return volume_devname;
}

static void ubi_check_dev(unsigned int dev_id)
{
	char *devname = (char *)DEVNAME(dev_id);
	char *pname;
	const char *volname = NULL;
	const char *volume_devname;

	if (!is_ubi_devname(DEVNAME(dev_id)))
		return;

	IS_UBI(dev_id) = 1;

	for (pname = devname; *pname != '\0'; pname++) {
		if (*pname == ':') {
			*pname = '\0';
			volname = pname + 1;
			break;
		}
	}

	if (volname) {
		/* Let's find real volume device name */
		volume_devname = ubi_get_volume_devname(devname, volname);
		if (!volume_devname) {
			fprintf(stderr, "Didn't found ubi volume \"%s\"\n",
				volname);
			return;
		}

		free(devname);
		DEVNAME(dev_id) = volume_devname;
	}
}

static int ubi_update_start(int fd, int64_t bytes)
{
	if (ioctl(fd, UBI_IOCVOLUP, &bytes))
		return -1;
	return 0;
}

static int ubi_read(int fd, void *buf, size_t count)
{
	ssize_t ret;

	while (count > 0) {
		ret = read(fd, buf, count);
		if (ret > 0) {
			count -= ret;
			buf += ret;

			continue;
		}

		if (ret == 0) {
			/*
			 * Happens in case of too short volume data size. If we
			 * return error status we will fail it will be treated
			 * as UBI device error.
			 *
			 * Leave catching this error to CRC check.
			 */
			fprintf(stderr, "Warning: end of data on ubi volume\n");
			return 0;
		} else if (errno == EBADF) {
			/*
			 * Happens in case of corrupted volume. The same as
			 * above, we cannot return error now, as we will still
			 * be able to successfully write environment later.
			 */
			fprintf(stderr, "Warning: corrupted volume?\n");
			return 0;
		} else if (errno == EINTR) {
			continue;
		}

		fprintf(stderr, "Cannot read %u bytes from ubi volume, %s\n",
			(unsigned int)count, strerror(errno));
		return -1;
	}

	return 0;
}

static int ubi_write(int fd, const void *buf, size_t count)
{
	ssize_t ret;

	while (count > 0) {
		ret = write(fd, buf, count);
		if (ret <= 0) {
			if (ret < 0 && errno == EINTR)
				continue;

			fprintf(stderr, "Cannot write %u bytes to ubi volume\n",
				(unsigned int)count);
			return -1;
		}

		count -= ret;
		buf += ret;
	}

	return 0;
}

A
Alex Kiernan 已提交
349
static int flash_io(int mode);
350
static int parse_config(struct env_opts *opts);
W
wdenk 已提交
351

352
#if defined(CONFIG_FILE)
A
Alex Kiernan 已提交
353
static int get_config(char *);
354
#endif
355

356
static char *skip_chars(char *s)
357
{
358
	for (; *s != '\0'; s++) {
359
		if (isblank(*s) || *s == '=')
360 361 362 363
			return s;
	}
	return NULL;
}
364

365 366 367 368
static char *skip_blanks(char *s)
{
	for (; *s != '\0'; s++) {
		if (!isblank(*s))
369
			return s;
370
	}
371
	return NULL;
372 373
}

374
/*
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
 * s1 is either a simple 'name', or a 'name=value' pair.
 * s2 is a 'name=value' pair.
 * If the names match, return the value of s2, else NULL.
 */
static char *envmatch(char *s1, char *s2)
{
	if (s1 == NULL || s2 == NULL)
		return NULL;

	while (*s1 == *s2++)
		if (*s1++ == '=')
			return s2;
	if (*s1 == '\0' && *(s2 - 1) == '=')
		return s2;
	return NULL;
}

/**
393 394 395
 * Search the environment for a variable.
 * Return the value, if found, or NULL, if not found.
 */
A
Alex Kiernan 已提交
396
char *fw_getenv(char *name)
397
{
398
	char *env, *nxt;
399

W
wdenk 已提交
400
	for (env = environment.data; *env; env = nxt + 1) {
401
		char *val;
402

W
wdenk 已提交
403
		for (nxt = env; *nxt; ++nxt) {
404
			if (nxt >= &environment.data[ENV_SIZE]) {
A
Alex Kiernan 已提交
405
				fprintf(stderr, "## Error: "
406
					"environment not terminated\n");
G
Guennadi Liakhovetski 已提交
407
				return NULL;
408 409
			}
		}
A
Alex Kiernan 已提交
410
		val = envmatch(name, env);
411 412
		if (!val)
			continue;
G
Guennadi Liakhovetski 已提交
413
		return val;
414
	}
G
Guennadi Liakhovetski 已提交
415
	return NULL;
416 417
}

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
/*
 * Search the default environment for a variable.
 * Return the value, if found, or NULL, if not found.
 */
char *fw_getdefenv(char *name)
{
	char *env, *nxt;

	for (env = default_environment; *env; env = nxt + 1) {
		char *val;

		for (nxt = env; *nxt; ++nxt) {
			if (nxt >= &default_environment[ENV_SIZE]) {
				fprintf(stderr, "## Error: "
					"default environment not terminated\n");
				return NULL;
			}
		}
		val = envmatch(name, env);
		if (!val)
			continue;
		return val;
	}
	return NULL;
}

444 445 446 447
/*
 * Print the current definition of one, or more, or all
 * environment variables
 */
448
int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
449
{
450
	int i, rc = 0;
451

452 453
	if (value_only && argc != 1) {
		fprintf(stderr,
A
Alex Kiernan 已提交
454
			"## Error: `-n'/`--noheader' option requires exactly one argument\n");
455 456 457
		return -1;
	}

458 459 460
	if (!opts)
		opts = &default_opts;

461
	if (fw_env_open(opts))
G
Guennadi Liakhovetski 已提交
462
		return -1;
463

A
Alex Kiernan 已提交
464
	if (argc == 0) {	/* Print all env variables  */
465
		char *env, *nxt;
W
wdenk 已提交
466 467
		for (env = environment.data; *env; env = nxt + 1) {
			for (nxt = env; *nxt; ++nxt) {
468
				if (nxt >= &environment.data[ENV_SIZE]) {
A
Alex Kiernan 已提交
469
					fprintf(stderr, "## Error: "
470
						"environment not terminated\n");
G
Guennadi Liakhovetski 已提交
471
					return -1;
472 473 474
				}
			}

A
Alex Kiernan 已提交
475
			printf("%s\n", env);
476
		}
477
		fw_env_close(opts);
G
Guennadi Liakhovetski 已提交
478
		return 0;
479 480
	}

481
	for (i = 0; i < argc; ++i) {	/* print a subset of env variables */
482 483
		char *name = argv[i];
		char *val = NULL;
484

485
		val = fw_getenv(name);
486
		if (!val) {
A
Alex Kiernan 已提交
487
			fprintf(stderr, "## Error: \"%s\" not defined\n", name);
488
			rc = -1;
489
			continue;
490
		}
491 492 493 494 495 496 497

		if (value_only) {
			puts(val);
			break;
		}

		printf("%s=%s\n", name, val);
498
	}
499

500 501
	fw_env_close(opts);

G
Guennadi Liakhovetski 已提交
502
	return rc;
503 504
}

505
int fw_env_flush(struct env_opts *opts)
506
{
507 508 509
	if (!opts)
		opts = &default_opts;

510 511 512
	if (!environment.dirty)
		return 0;

513 514 515 516
	/*
	 * Update CRC
	 */
	*environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
517

518 519
	/* write environment back to flash */
	if (flash_io(O_RDWR)) {
A
Alex Kiernan 已提交
520 521
		fprintf(stderr, "Error: can't write fw_env to flash\n");
		return -1;
522 523
	}

524 525
	return 0;
}
526

527 528 529 530 531 532 533 534 535 536
/*
 * Set/Clear a single variable in the environment.
 * This is called in sequence to update the environment
 * in RAM without updating the copy in flash after each set
 */
int fw_env_write(char *name, char *value)
{
	int len;
	char *env, *nxt;
	char *oldval = NULL;
537
	int deleting, creating, overwriting;
538 539 540 541

	/*
	 * search if variable with this name already exists
	 */
W
wdenk 已提交
542 543
	for (nxt = env = environment.data; *env; env = nxt + 1) {
		for (nxt = env; *nxt; ++nxt) {
544
			if (nxt >= &environment.data[ENV_SIZE]) {
545
				fprintf(stderr, "## Error: "
546
					"environment not terminated\n");
G
Guennadi Liakhovetski 已提交
547 548
				errno = EINVAL;
				return -1;
549 550
			}
		}
A
Alex Kiernan 已提交
551 552
		oldval = envmatch(name, env);
		if (oldval)
553 554 555
			break;
	}

556 557
	deleting = (oldval && !(value && strlen(value)));
	creating = (!oldval && (value && strlen(value)));
558 559
	overwriting = (oldval && (value && strlen(value) &&
				  strcmp(oldval, value)));
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575

	/* check for permission */
	if (deleting) {
		if (env_flags_validate_varaccess(name,
		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
			printf("Can't delete \"%s\"\n", name);
			errno = EROFS;
			return -1;
		}
	} else if (overwriting) {
		if (env_flags_validate_varaccess(name,
		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
			printf("Can't overwrite \"%s\"\n", name);
			errno = EROFS;
			return -1;
		} else if (env_flags_validate_varaccess(name,
A
Alex Kiernan 已提交
576
			   ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
			const char *defval = fw_getdefenv(name);

			if (defval == NULL)
				defval = "";
			if (strcmp(oldval, defval)
			    != 0) {
				printf("Can't overwrite \"%s\"\n", name);
				errno = EROFS;
				return -1;
			}
		}
	} else if (creating) {
		if (env_flags_validate_varaccess(name,
		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
			printf("Can't create \"%s\"\n", name);
			errno = EROFS;
			return -1;
		}
	} else
		/* Nothing to do */
		return 0;

599
	environment.dirty = 1;
600
	if (deleting || overwriting) {
601 602 603 604 605 606 607 608 609 610 611 612 613 614
		if (*++nxt == '\0') {
			*env = '\0';
		} else {
			for (;;) {
				*env = *nxt++;
				if ((*env == '\0') && (*nxt == '\0'))
					break;
				++env;
			}
		}
		*++env = '\0';
	}

	/* Delete only ? */
615 616
	if (!value || !strlen(value))
		return 0;
617 618 619 620

	/*
	 * Append new definition at the end
	 */
A
Alex Kiernan 已提交
621 622
	for (env = environment.data; *env || *(env + 1); ++env)
		;
623 624 625 626
	if (env > environment.data)
		++env;
	/*
	 * Overflow when:
627
	 * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
628
	 */
A
Alex Kiernan 已提交
629
	len = strlen(name) + 2;
630
	/* add '=' for first arg, ' ' for all others */
631 632
	len += strlen(value) + 1;

W
wdenk 已提交
633
	if (len > (&environment.data[ENV_SIZE] - env)) {
A
Alex Kiernan 已提交
634 635
		fprintf(stderr,
			"Error: environment overflow, \"%s\" deleted\n", name);
G
Guennadi Liakhovetski 已提交
636
		return -1;
637
	}
638

639 640
	while ((*env = *name++) != '\0')
		env++;
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
	*env = '=';
	while ((*++env = *value++) != '\0')
		;

	/* end is marked with double '\0' */
	*++env = '\0';

	return 0;
}

/*
 * Deletes or sets environment variables. Returns -1 and sets errno error codes:
 * 0	  - OK
 * EINVAL - need at least 1 argument
 * EROFS  - certain variables ("ethaddr", "serial#") cannot be
 *	    modified or deleted
 *
 */
S
Simon Glass 已提交
659
int fw_env_set(int argc, char *argv[], struct env_opts *opts)
660
{
661
	int i;
M
Mike Frysinger 已提交
662
	size_t len;
663
	char *name, **valv;
664
	char *oldval;
665
	char *value = NULL;
666
	int valc;
667
	int ret;
668

669 670 671
	if (!opts)
		opts = &default_opts;

672 673
	if (argc < 1) {
		fprintf(stderr, "## Error: variable name missing\n");
674 675 676 677
		errno = EINVAL;
		return -1;
	}

678
	if (fw_env_open(opts)) {
679 680 681 682
		fprintf(stderr, "Error: environment not initialized\n");
		return -1;
	}

683 684 685
	name = argv[0];
	valv = argv + 1;
	valc = argc - 1;
686

687 688
	if (env_flags_validate_env_set_params(name, valv, valc) < 0) {
		fw_env_close(opts);
689
		return -1;
690
	}
691

692
	len = 0;
693 694
	for (i = 0; i < valc; ++i) {
		char *val = valv[i];
695 696
		size_t val_len = strlen(val);

697 698
		if (value)
			value[len - 1] = ' ';
699
		oldval = value;
700
		value = realloc(value, len + val_len + 1);
701
		if (!value) {
702
			fprintf(stderr,
L
Luka Perkov 已提交
703
				"Cannot malloc %zu bytes: %s\n",
704
				len, strerror(errno));
705
			free(oldval);
706
			return -1;
707
		}
708 709 710

		memcpy(value + len, val, val_len);
		len += val_len;
711
		value[len++] = '\0';
712 713
	}

714
	fw_env_write(name, value);
715

716
	free(value);
717

718 719 720 721
	ret = fw_env_flush(opts);
	fw_env_close(opts);

	return ret;
722
}
723

724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
/*
 * Parse  a file  and configure the u-boot variables.
 * The script file has a very simple format, as follows:
 *
 * Each line has a couple with name, value:
 * <white spaces>variable_name<white spaces>variable_value
 *
 * Both variable_name and variable_value are interpreted as strings.
 * Any character after <white spaces> and before ending \r\n is interpreted
 * as variable's value (no comment allowed on these lines !)
 *
 * Comments are allowed if the first character in the line is #
 *
 * Returns -1 and sets errno error codes:
 * 0	  - OK
 * -1     - Error
 */
741
int fw_parse_script(char *fname, struct env_opts *opts)
742 743
{
	FILE *fp;
744 745
	char *line = NULL;
	size_t linesize = 0;
746 747 748 749 750 751
	char *name;
	char *val;
	int lineno = 0;
	int len;
	int ret = 0;

752 753 754
	if (!opts)
		opts = &default_opts;

755
	if (fw_env_open(opts)) {
756
		fprintf(stderr, "Error: environment not initialized\n");
G
Guennadi Liakhovetski 已提交
757
		return -1;
758 759
	}

760 761 762 763 764 765
	if (strcmp(fname, "-") == 0)
		fp = stdin;
	else {
		fp = fopen(fname, "r");
		if (fp == NULL) {
			fprintf(stderr, "I cannot open %s for reading\n",
A
Alex Kiernan 已提交
766
				fname);
767 768 769 770
			return -1;
		}
	}

771
	while ((len = getline(&line, &linesize, fp)) != -1) {
772 773 774
		lineno++;

		/*
775 776
		 * Read a whole line from the file. If the line is not
		 * terminated, reports an error and exit.
777
		 */
778
		if (line[len - 1] != '\n') {
779
			fprintf(stderr,
780
				"Line %d not correctly terminated\n",
781 782 783 784 785 786
				lineno);
			ret = -1;
			break;
		}

		/* Drop ending line feed / carriage return */
787 788 789
		line[--len] = '\0';
		if (len && line[len - 1] == '\r')
			line[--len] = '\0';
790 791

		/* Skip comment or empty lines */
792
		if (len == 0 || line[0] == '#')
793 794 795
			continue;

		/*
796
		 * Search for variable's name remove leading whitespaces
797
		 */
798
		name = skip_blanks(line);
799 800 801 802
		if (!name)
			continue;

		/* The first white space is the end of variable name */
803
		val = skip_chars(name);
804 805 806 807
		len = strlen(name);
		if (val) {
			*val++ = '\0';
			if ((val - name) < len)
808
				val = skip_blanks(val);
809 810 811 812 813 814 815 816
			else
				val = NULL;
		}
#ifdef DEBUG
		fprintf(stderr, "Setting %s : %s\n",
			name, val ? val : " removed");
#endif

817 818 819 820 821
		if (env_flags_validate_type(name, val) < 0) {
			ret = -1;
			break;
		}

822 823 824 825 826 827
		/*
		 * If there is an error setting a variable,
		 * try to save the environment and returns an error
		 */
		if (fw_env_write(name, val)) {
			fprintf(stderr,
A
Alex Kiernan 已提交
828
				"fw_env_write returns with error : %s\n",
829 830 831 832 833 834
				strerror(errno));
			ret = -1;
			break;
		}

	}
835
	free(line);
836 837 838 839 840

	/* Close file if not stdin */
	if (strcmp(fname, "-") != 0)
		fclose(fp);

841 842 843
	ret |= fw_env_flush(opts);

	fw_env_close(opts);
844 845

	return ret;
846 847
}

848
/**
S
Shyam Saini 已提交
849
 * environment_end() - compute offset of first byte right after environment
850 851
 * @dev - index of enviroment buffer
 * Return:
S
Shyam Saini 已提交
852
 *  device offset of first byte right after environment
853 854 855 856 857 858 859
 */
off_t environment_end(int dev)
{
	/* environment is block aligned */
	return DEVOFFSET(dev) + ENVSECTORS(dev) * DEVESIZE(dev);
}

G
Guennadi Liakhovetski 已提交
860 861 862 863 864 865
/*
 * Test for bad block on NAND, just returns 0 on NOR, on NAND:
 * 0	- block is good
 * > 0	- block is bad
 * < 0	- failed to test
 */
866
static int flash_bad_block(int fd, uint8_t mtd_type, loff_t blockstart)
867
{
G
Guennadi Liakhovetski 已提交
868
	if (mtd_type == MTD_NANDFLASH) {
869
		int badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart);
870

G
Guennadi Liakhovetski 已提交
871
		if (badblock < 0) {
A
Alex Kiernan 已提交
872
			perror("Cannot read bad block mark");
G
Guennadi Liakhovetski 已提交
873 874 875 876 877
			return badblock;
		}

		if (badblock) {
#ifdef DEBUG
A
Alex Kiernan 已提交
878
			fprintf(stderr, "Bad block at 0x%llx, skipping\n",
879
				(unsigned long long)blockstart);
G
Guennadi Liakhovetski 已提交
880 881 882
#endif
			return badblock;
		}
883 884
	}

G
Guennadi Liakhovetski 已提交
885 886 887 888 889 890 891 892
	return 0;
}

/*
 * Read data from flash at an offset into a provided buffer. On NAND it skips
 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
 * the DEVOFFSET (dev) block. On NOR the loop is only run once.
 */
A
Alex Kiernan 已提交
893 894
static int flash_read_buf(int dev, int fd, void *buf, size_t count,
			  off_t offset)
G
Guennadi Liakhovetski 已提交
895 896 897 898 899 900 901 902 903 904 905
{
	size_t blocklen;	/* erase / write length - one block on NAND,
				   0 on NOR */
	size_t processed = 0;	/* progress counter */
	size_t readlen = count;	/* current read length */
	off_t block_seek;	/* offset inside the current block to the start
				   of the data */
	loff_t blockstart;	/* running start of the current block -
				   MEMGETBADBLOCK needs 64 bits */
	int rc;

A
Alex Kiernan 已提交
906
	blockstart = (offset / DEVESIZE(dev)) * DEVESIZE(dev);
G
Guennadi Liakhovetski 已提交
907 908 909 910

	/* Offset inside a block */
	block_seek = offset - blockstart;

911
	if (DEVTYPE(dev) == MTD_NANDFLASH) {
G
Guennadi Liakhovetski 已提交
912 913 914 915
		/*
		 * NAND: calculate which blocks we are reading. We have
		 * to read one block at a time to skip bad blocks.
		 */
A
Alex Kiernan 已提交
916
		blocklen = DEVESIZE(dev);
G
Guennadi Liakhovetski 已提交
917 918 919 920 921 922

		/* Limit to one block for the first read */
		if (readlen > blocklen - block_seek)
			readlen = blocklen - block_seek;
	} else {
		blocklen = 0;
923
	}
924

G
Guennadi Liakhovetski 已提交
925 926
	/* This only runs once on NOR flash */
	while (processed < count) {
927
		rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
A
Alex Kiernan 已提交
928
		if (rc < 0)	/* block test failed */
G
Guennadi Liakhovetski 已提交
929
			return -1;
930

931
		if (blockstart + block_seek + readlen > environment_end(dev)) {
G
Guennadi Liakhovetski 已提交
932
			/* End of range is reached */
A
Alex Kiernan 已提交
933
			fprintf(stderr, "Too few good blocks within range\n");
G
Guennadi Liakhovetski 已提交
934
			return -1;
935 936
		}

A
Alex Kiernan 已提交
937
		if (rc) {	/* block is bad */
G
Guennadi Liakhovetski 已提交
938 939
			blockstart += blocklen;
			continue;
940 941
		}

G
Guennadi Liakhovetski 已提交
942 943
		/*
		 * If a block is bad, we retry in the next block at the same
944
		 * offset - see env/nand.c::writeenv()
G
Guennadi Liakhovetski 已提交
945
		 */
A
Alex Kiernan 已提交
946
		lseek(fd, blockstart + block_seek, SEEK_SET);
947

A
Alex Kiernan 已提交
948
		rc = read(fd, buf + processed, readlen);
G
Guennadi Liakhovetski 已提交
949
		if (rc != readlen) {
A
Alex Kiernan 已提交
950 951
			fprintf(stderr, "Read error on %s: %s\n",
				DEVNAME(dev), strerror(errno));
G
Guennadi Liakhovetski 已提交
952
			return -1;
953
		}
G
Guennadi Liakhovetski 已提交
954
#ifdef DEBUG
J
Joe Hershberger 已提交
955
		fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
A
Alex Kiernan 已提交
956
			rc, (unsigned long long)blockstart + block_seek,
957
			DEVNAME(dev));
G
Guennadi Liakhovetski 已提交
958 959
#endif
		processed += readlen;
A
Alex Kiernan 已提交
960
		readlen = min(blocklen, count - processed);
G
Guennadi Liakhovetski 已提交
961 962 963 964 965 966 967 968
		block_seek = 0;
		blockstart += blocklen;
	}

	return processed;
}

/*
969 970
 * Write count bytes from begin of environment, but stay within
 * ENVSECTORS(dev) sectors of
971 972
 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
 * erase and write the whole data at once.
G
Guennadi Liakhovetski 已提交
973
 */
974
static int flash_write_buf(int dev, int fd, void *buf, size_t count)
G
Guennadi Liakhovetski 已提交
975 976 977 978 979 980 981 982 983
{
	void *data;
	struct erase_info_user erase;
	size_t blocklen;	/* length of NAND block / NOR erase sector */
	size_t erase_len;	/* whole area that can be erased - may include
				   bad blocks */
	size_t erasesize;	/* erase / write length - one block on NAND,
				   whole area on NOR */
	size_t processed = 0;	/* progress counter */
984
	size_t write_total;	/* total size to actually write - excluding
G
Guennadi Liakhovetski 已提交
985 986 987 988 989 990 991 992 993
				   bad blocks */
	off_t erase_offset;	/* offset to the first erase block (aligned)
				   below offset */
	off_t block_seek;	/* offset inside the erase block to the start
				   of the data */
	loff_t blockstart;	/* running start of the current block -
				   MEMGETBADBLOCK needs 64 bits */
	int rc;

994 995 996
	/*
	 * For mtd devices only offset and size of the environment do matter
	 */
997
	if (DEVTYPE(dev) == MTD_ABSENT) {
998 999
		blocklen = count;
		erase_len = blocklen;
1000
		blockstart = DEVOFFSET(dev);
1001 1002 1003 1004
		block_seek = 0;
		write_total = blocklen;
	} else {
		blocklen = DEVESIZE(dev);
G
Guennadi Liakhovetski 已提交
1005

1006
		erase_offset = DEVOFFSET(dev);
1007

1008
		/* Maximum area we may use */
1009
		erase_len = environment_end(dev) - erase_offset;
G
Guennadi Liakhovetski 已提交
1010

1011
		blockstart = erase_offset;
1012

1013
		/* Offset inside a block */
1014
		block_seek = DEVOFFSET(dev) - erase_offset;
G
Guennadi Liakhovetski 已提交
1015

1016 1017 1018 1019 1020 1021
		/*
		 * Data size we actually write: from the start of the block
		 * to the start of the data, then count bytes of data, and
		 * to the end of the block
		 */
		write_total = ((block_seek + count + blocklen - 1) /
A
Alex Kiernan 已提交
1022
			       blocklen) * blocklen;
1023
	}
G
Guennadi Liakhovetski 已提交
1024 1025 1026 1027 1028 1029 1030

	/*
	 * Support data anywhere within erase sectors: read out the complete
	 * area to be erased, replace the environment image, write the whole
	 * block back again.
	 */
	if (write_total > count) {
A
Alex Kiernan 已提交
1031
		data = malloc(erase_len);
G
Guennadi Liakhovetski 已提交
1032
		if (!data) {
A
Alex Kiernan 已提交
1033 1034 1035
			fprintf(stderr,
				"Cannot malloc %zu bytes: %s\n",
				erase_len, strerror(errno));
G
Guennadi Liakhovetski 已提交
1036
			return -1;
1037
		}
G
Guennadi Liakhovetski 已提交
1038

1039
		rc = flash_read_buf(dev, fd, data, write_total, erase_offset);
G
Guennadi Liakhovetski 已提交
1040 1041 1042
		if (write_total != rc)
			return -1;

J
Joe Hershberger 已提交
1043 1044 1045 1046 1047 1048 1049
#ifdef DEBUG
		fprintf(stderr, "Preserving data ");
		if (block_seek != 0)
			fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1);
		if (block_seek + count != write_total) {
			if (block_seek != 0)
				fprintf(stderr, " and ");
1050
			fprintf(stderr, "0x%lx - 0x%lx",
A
Alex Kiernan 已提交
1051 1052
				(unsigned long)block_seek + count,
				(unsigned long)write_total - 1);
J
Joe Hershberger 已提交
1053 1054 1055
		}
		fprintf(stderr, "\n");
#endif
G
Guennadi Liakhovetski 已提交
1056
		/* Overwrite the old environment */
A
Alex Kiernan 已提交
1057
		memcpy(data + block_seek, buf, count);
G
Guennadi Liakhovetski 已提交
1058 1059 1060 1061 1062 1063 1064 1065
	} else {
		/*
		 * We get here, iff offset is block-aligned and count is a
		 * multiple of blocklen - see write_total calculation above
		 */
		data = buf;
	}

1066
	if (DEVTYPE(dev) == MTD_NANDFLASH) {
G
Guennadi Liakhovetski 已提交
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
		/*
		 * NAND: calculate which blocks we are writing. We have
		 * to write one block at a time to skip bad blocks.
		 */
		erasesize = blocklen;
	} else {
		erasesize = erase_len;
	}

	erase.length = erasesize;

1078
	/* This only runs once on NOR flash and SPI-dataflash */
G
Guennadi Liakhovetski 已提交
1079
	while (processed < write_total) {
1080
		rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
A
Alex Kiernan 已提交
1081
		if (rc < 0)	/* block test failed */
G
Guennadi Liakhovetski 已提交
1082 1083
			return rc;

1084
		if (blockstart + erasesize > environment_end(dev)) {
A
Alex Kiernan 已提交
1085
			fprintf(stderr, "End of range reached, aborting\n");
G
Guennadi Liakhovetski 已提交
1086
			return -1;
1087
		}
G
Guennadi Liakhovetski 已提交
1088

A
Alex Kiernan 已提交
1089
		if (rc) {	/* block is bad */
G
Guennadi Liakhovetski 已提交
1090 1091 1092 1093
			blockstart += blocklen;
			continue;
		}

1094
		if (DEVTYPE(dev) != MTD_ABSENT) {
1095 1096 1097
			erase.start = blockstart;
			ioctl(fd, MEMUNLOCK, &erase);
			/* These do not need an explicit erase cycle */
1098
			if (DEVTYPE(dev) != MTD_DATAFLASH)
1099 1100 1101 1102 1103 1104 1105
				if (ioctl(fd, MEMERASE, &erase) != 0) {
					fprintf(stderr,
						"MTD erase error on %s: %s\n",
						DEVNAME(dev), strerror(errno));
					return -1;
				}
		}
G
Guennadi Liakhovetski 已提交
1106

A
Alex Kiernan 已提交
1107 1108 1109 1110
		if (lseek(fd, blockstart, SEEK_SET) == -1) {
			fprintf(stderr,
				"Seek error on %s: %s\n",
				DEVNAME(dev), strerror(errno));
G
Guennadi Liakhovetski 已提交
1111
			return -1;
1112
		}
G
Guennadi Liakhovetski 已提交
1113
#ifdef DEBUG
1114
		fprintf(stderr, "Write 0x%llx bytes at 0x%llx\n",
A
Alex Kiernan 已提交
1115 1116
			(unsigned long long)erasesize,
			(unsigned long long)blockstart);
G
Guennadi Liakhovetski 已提交
1117
#endif
A
Alex Kiernan 已提交
1118 1119 1120
		if (write(fd, data + processed, erasesize) != erasesize) {
			fprintf(stderr, "Write error on %s: %s\n",
				DEVNAME(dev), strerror(errno));
G
Guennadi Liakhovetski 已提交
1121
			return -1;
1122
		}
G
Guennadi Liakhovetski 已提交
1123

1124
		if (DEVTYPE(dev) != MTD_ABSENT)
1125
			ioctl(fd, MEMLOCK, &erase);
G
Guennadi Liakhovetski 已提交
1126

A
Alex Kiernan 已提交
1127
		processed += erasesize;
G
Guennadi Liakhovetski 已提交
1128
		block_seek = 0;
1129
		blockstart += erasesize;
G
Guennadi Liakhovetski 已提交
1130 1131 1132
	}

	if (write_total > count)
A
Alex Kiernan 已提交
1133
		free(data);
G
Guennadi Liakhovetski 已提交
1134 1135 1136 1137 1138 1139 1140

	return processed;
}

/*
 * Set obsolete flag at offset - NOR flash only
 */
A
Alex Kiernan 已提交
1141
static int flash_flag_obsolete(int dev, int fd, off_t offset)
G
Guennadi Liakhovetski 已提交
1142 1143
{
	int rc;
1144
	struct erase_info_user erase;
P
Pierre-Jean Texier 已提交
1145
	char tmp = ENV_REDUND_OBSOLETE;
G
Guennadi Liakhovetski 已提交
1146

A
Alex Kiernan 已提交
1147 1148
	erase.start = DEVOFFSET(dev);
	erase.length = DEVESIZE(dev);
S
Simon Glass 已提交
1149
	/* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */
A
Alex Kiernan 已提交
1150
	rc = lseek(fd, offset, SEEK_SET);
G
Guennadi Liakhovetski 已提交
1151
	if (rc < 0) {
A
Alex Kiernan 已提交
1152 1153
		fprintf(stderr, "Cannot seek to set the flag on %s\n",
			DEVNAME(dev));
G
Guennadi Liakhovetski 已提交
1154 1155
		return rc;
	}
A
Alex Kiernan 已提交
1156
	ioctl(fd, MEMUNLOCK, &erase);
P
Pierre-Jean Texier 已提交
1157
	rc = write(fd, &tmp, sizeof(tmp));
A
Alex Kiernan 已提交
1158
	ioctl(fd, MEMLOCK, &erase);
G
Guennadi Liakhovetski 已提交
1159
	if (rc < 0)
A
Alex Kiernan 已提交
1160
		perror("Could not set obsolete flag");
G
Guennadi Liakhovetski 已提交
1161 1162 1163 1164

	return rc;
}

A
Alex Kiernan 已提交
1165
static int flash_write(int fd_current, int fd_target, int dev_target)
G
Guennadi Liakhovetski 已提交
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
{
	int rc;

	switch (environment.flag_scheme) {
	case FLAG_NONE:
		break;
	case FLAG_INCREMENTAL:
		(*environment.flags)++;
		break;
	case FLAG_BOOLEAN:
S
Simon Glass 已提交
1176
		*environment.flags = ENV_REDUND_ACTIVE;
G
Guennadi Liakhovetski 已提交
1177 1178
		break;
	default:
A
Alex Kiernan 已提交
1179 1180
		fprintf(stderr, "Unimplemented flash scheme %u\n",
			environment.flag_scheme);
G
Guennadi Liakhovetski 已提交
1181 1182 1183 1184
		return -1;
	}

#ifdef DEBUG
S
Stefan Agner 已提交
1185
	fprintf(stderr, "Writing new environment at 0x%llx on %s\n",
A
Alex Kiernan 已提交
1186
		DEVOFFSET(dev_target), DEVNAME(dev_target));
G
Guennadi Liakhovetski 已提交
1187
#endif
1188

1189 1190 1191 1192 1193 1194
	if (IS_UBI(dev_target)) {
		if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0)
			return 0;
		return ubi_write(fd_target, environment.image, CUR_ENVSIZE);
	}

1195
	rc = flash_write_buf(dev_target, fd_target, environment.image,
1196
			     CUR_ENVSIZE);
G
Guennadi Liakhovetski 已提交
1197 1198 1199 1200 1201
	if (rc < 0)
		return rc;

	if (environment.flag_scheme == FLAG_BOOLEAN) {
		/* Have to set obsolete flag */
A
Alex Kiernan 已提交
1202 1203
		off_t offset = DEVOFFSET(dev_current) +
		    offsetof(struct env_image_redundant, flags);
G
Guennadi Liakhovetski 已提交
1204
#ifdef DEBUG
J
Joe Hershberger 已提交
1205
		fprintf(stderr,
S
Stefan Agner 已提交
1206
			"Setting obsolete flag in environment at 0x%llx on %s\n",
A
Alex Kiernan 已提交
1207
			DEVOFFSET(dev_current), DEVNAME(dev_current));
G
Guennadi Liakhovetski 已提交
1208
#endif
A
Alex Kiernan 已提交
1209
		flash_flag_obsolete(dev_current, fd_current, offset);
G
Guennadi Liakhovetski 已提交
1210 1211 1212 1213 1214
	}

	return 0;
}

A
Alex Kiernan 已提交
1215
static int flash_read(int fd)
G
Guennadi Liakhovetski 已提交
1216 1217 1218
{
	int rc;

1219 1220 1221 1222 1223 1224
	if (IS_UBI(dev_current)) {
		DEVTYPE(dev_current) = MTD_ABSENT;

		return ubi_read(fd, environment.image, CUR_ENVSIZE);
	}

1225
	rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
1226
			    DEVOFFSET(dev_current));
1227 1228
	if (rc != CUR_ENVSIZE)
		return -1;
G
Guennadi Liakhovetski 已提交
1229

1230
	return 0;
G
Guennadi Liakhovetski 已提交
1231 1232
}

1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
static int flash_open_tempfile(const char **dname, const char **target_temp)
{
	char *dup_name = strdup(DEVNAME(dev_current));
	char *temp_name = NULL;
	int rc = -1;

	if (!dup_name)
		return -1;

	*dname = dirname(dup_name);
	if (!*dname)
		goto err;

	rc = asprintf(&temp_name, "%s/XXXXXX", *dname);
	if (rc == -1)
		goto err;

	rc = mkstemp(temp_name);
	if (rc == -1) {
		/* fall back to in place write */
		fprintf(stderr,
			"Can't create %s: %s\n", temp_name, strerror(errno));
		free(temp_name);
	} else {
		*target_temp = temp_name;
		/* deliberately leak dup_name as dname /might/ point into
		 * it and we need it for our caller
		 */
		dup_name = NULL;
	}

err:
	if (dup_name)
		free(dup_name);

	return rc;
}

1271 1272
static int flash_io_write(int fd_current)
{
1273 1274
	int fd_target = -1, rc, dev_target;
	const char *dname, *target_temp = NULL;
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288

	if (have_redund_env) {
		/* switch to next partition for writing */
		dev_target = !dev_current;
		/* dev_target: fd_target, erase_target */
		fd_target = open(DEVNAME(dev_target), O_RDWR);
		if (fd_target < 0) {
			fprintf(stderr,
				"Can't open %s: %s\n",
				DEVNAME(dev_target), strerror(errno));
			rc = -1;
			goto exit;
		}
	} else {
1289 1290 1291 1292 1293 1294 1295 1296
		struct stat sb;

		if (fstat(fd_current, &sb) == 0 && S_ISREG(sb.st_mode)) {
			/* if any part of flash_open_tempfile() fails we fall
			 * back to in-place writes
			 */
			fd_target = flash_open_tempfile(&dname, &target_temp);
		}
1297
		dev_target = dev_current;
1298 1299
		if (fd_target == -1)
			fd_target = fd_current;
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
	}

	rc = flash_write(fd_current, fd_target, dev_target);

	if (fsync(fd_current) && !(errno == EINVAL || errno == EROFS)) {
		fprintf(stderr,
			"fsync failed on %s: %s\n",
			DEVNAME(dev_current), strerror(errno));
	}

1310
	if (fd_current != fd_target) {
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
		if (fsync(fd_target) &&
		    !(errno == EINVAL || errno == EROFS)) {
			fprintf(stderr,
				"fsync failed on %s: %s\n",
				DEVNAME(dev_current), strerror(errno));
		}

		if (close(fd_target)) {
			fprintf(stderr,
				"I/O error on %s: %s\n",
				DEVNAME(dev_target), strerror(errno));
			rc = -1;
		}
1324

1325
		if (rc >= 0 && target_temp) {
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
			int dir_fd;

			dir_fd = open(dname, O_DIRECTORY | O_RDONLY);
			if (dir_fd == -1)
				fprintf(stderr,
					"Can't open %s: %s\n",
					dname, strerror(errno));

			if (rename(target_temp, DEVNAME(dev_target))) {
				fprintf(stderr,
					"rename failed %s => %s: %s\n",
					target_temp, DEVNAME(dev_target),
					strerror(errno));
				rc = -1;
			}

			if (dir_fd != -1 && fsync(dir_fd))
				fprintf(stderr,
					"fsync failed on %s: %s\n",
					dname, strerror(errno));

			if (dir_fd != -1 && close(dir_fd))
				fprintf(stderr,
					"I/O error on %s: %s\n",
					dname, strerror(errno));
		}
1352 1353 1354 1355 1356
	}
 exit:
	return rc;
}

A
Alex Kiernan 已提交
1357
static int flash_io(int mode)
G
Guennadi Liakhovetski 已提交
1358
{
1359
	int fd_current, rc;
G
Guennadi Liakhovetski 已提交
1360 1361

	/* dev_current: fd_current, erase_current */
A
Alex Kiernan 已提交
1362
	fd_current = open(DEVNAME(dev_current), mode);
G
Guennadi Liakhovetski 已提交
1363
	if (fd_current < 0) {
A
Alex Kiernan 已提交
1364 1365 1366
		fprintf(stderr,
			"Can't open %s: %s\n",
			DEVNAME(dev_current), strerror(errno));
G
Guennadi Liakhovetski 已提交
1367 1368 1369 1370
		return -1;
	}

	if (mode == O_RDWR) {
1371
		rc = flash_io_write(fd_current);
1372
	} else {
A
Alex Kiernan 已提交
1373
		rc = flash_read(fd_current);
1374 1375
	}

A
Alex Kiernan 已提交
1376 1377 1378 1379
	if (close(fd_current)) {
		fprintf(stderr,
			"I/O error on %s: %s\n",
			DEVNAME(dev_current), strerror(errno));
G
Guennadi Liakhovetski 已提交
1380
		return -1;
1381 1382
	}

G
Guennadi Liakhovetski 已提交
1383
	return rc;
1384 1385 1386 1387 1388
}

/*
 * Prevent confusion if running from erased flash memory
 */
1389
int fw_env_open(struct env_opts *opts)
1390
{
G
Guennadi Liakhovetski 已提交
1391
	int crc0, crc0_ok;
1392
	unsigned char flag0;
1393
	void *addr0 = NULL;
G
Guennadi Liakhovetski 已提交
1394

1395
	int crc1, crc1_ok;
1396
	unsigned char flag1;
1397
	void *addr1 = NULL;
1398

1399 1400
	int ret;

G
Guennadi Liakhovetski 已提交
1401 1402
	struct env_image_single *single;
	struct env_image_redundant *redundant;
1403

1404 1405 1406
	if (!opts)
		opts = &default_opts;

A
Alex Kiernan 已提交
1407
	if (parse_config(opts))	/* should fill envdevices */
1408
		return -EINVAL;
W
wdenk 已提交
1409

1410
	addr0 = calloc(1, CUR_ENVSIZE);
G
Guennadi Liakhovetski 已提交
1411
	if (addr0 == NULL) {
1412
		fprintf(stderr,
W
wdenk 已提交
1413
			"Not enough memory for environment (%ld bytes)\n",
1414
			CUR_ENVSIZE);
1415 1416
		ret = -ENOMEM;
		goto open_cleanup;
1417
	}
W
wdenk 已提交
1418

1419
	/* read environment from FLASH to local buffer */
G
Guennadi Liakhovetski 已提交
1420 1421
	environment.image = addr0;

1422
	if (have_redund_env) {
G
Guennadi Liakhovetski 已提交
1423
		redundant = addr0;
A
Alex Kiernan 已提交
1424 1425 1426
		environment.crc = &redundant->crc;
		environment.flags = &redundant->flags;
		environment.data = redundant->data;
G
Guennadi Liakhovetski 已提交
1427 1428
	} else {
		single = addr0;
A
Alex Kiernan 已提交
1429 1430 1431
		environment.crc = &single->crc;
		environment.flags = NULL;
		environment.data = single->data;
1432
	}
W
wdenk 已提交
1433

G
Guennadi Liakhovetski 已提交
1434
	dev_current = 0;
1435
	if (flash_io(O_RDONLY)) {
1436 1437 1438
		ret = -EIO;
		goto open_cleanup;
	}
G
Guennadi Liakhovetski 已提交
1439

1440 1441 1442
	crc0 = crc32(0, (uint8_t *)environment.data, ENV_SIZE);

	crc0_ok = (crc0 == *environment.crc);
1443
	if (!have_redund_env) {
G
Guennadi Liakhovetski 已提交
1444
		if (!crc0_ok) {
A
Alex Kiernan 已提交
1445
			fprintf(stderr,
W
wdenk 已提交
1446
				"Warning: Bad CRC, using default environment\n");
A
Alex Kiernan 已提交
1447 1448
			memcpy(environment.data, default_environment,
			       sizeof(default_environment));
1449
			environment.dirty = 1;
1450
		}
1451
	} else {
G
Guennadi Liakhovetski 已提交
1452
		flag0 = *environment.flags;
W
wdenk 已提交
1453

G
Guennadi Liakhovetski 已提交
1454
		dev_current = 1;
1455
		addr1 = calloc(1, CUR_ENVSIZE);
G
Guennadi Liakhovetski 已提交
1456
		if (addr1 == NULL) {
1457
			fprintf(stderr,
W
wdenk 已提交
1458
				"Not enough memory for environment (%ld bytes)\n",
1459
				CUR_ENVSIZE);
1460 1461
			ret = -ENOMEM;
			goto open_cleanup;
W
wdenk 已提交
1462
		}
G
Guennadi Liakhovetski 已提交
1463
		redundant = addr1;
W
wdenk 已提交
1464

G
Guennadi Liakhovetski 已提交
1465 1466 1467 1468 1469
		/*
		 * have to set environment.image for flash_read(), careful -
		 * other pointers in environment still point inside addr0
		 */
		environment.image = addr1;
1470
		if (flash_io(O_RDONLY)) {
1471 1472
			ret = -EIO;
			goto open_cleanup;
1473
		}
G
Guennadi Liakhovetski 已提交
1474 1475 1476 1477 1478 1479 1480 1481

		/* Check flag scheme compatibility */
		if (DEVTYPE(dev_current) == MTD_NORFLASH &&
		    DEVTYPE(!dev_current) == MTD_NORFLASH) {
			environment.flag_scheme = FLAG_BOOLEAN;
		} else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
			   DEVTYPE(!dev_current) == MTD_NANDFLASH) {
			environment.flag_scheme = FLAG_INCREMENTAL;
1482 1483 1484
		} else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
			   DEVTYPE(!dev_current) == MTD_DATAFLASH) {
			environment.flag_scheme = FLAG_BOOLEAN;
1485 1486 1487
		} else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
			   DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
			environment.flag_scheme = FLAG_INCREMENTAL;
1488
		} else if (DEVTYPE(dev_current) == MTD_ABSENT &&
1489 1490
			   DEVTYPE(!dev_current) == MTD_ABSENT &&
			   IS_UBI(dev_current) == IS_UBI(!dev_current)) {
1491
			environment.flag_scheme = FLAG_INCREMENTAL;
G
Guennadi Liakhovetski 已提交
1492
		} else {
A
Alex Kiernan 已提交
1493
			fprintf(stderr, "Incompatible flash types!\n");
1494 1495
			ret = -EINVAL;
			goto open_cleanup;
1496
		}
W
wdenk 已提交
1497

1498 1499 1500
		crc1 = crc32(0, (uint8_t *)redundant->data, ENV_SIZE);

		crc1_ok = (crc1 == redundant->crc);
G
Guennadi Liakhovetski 已提交
1501 1502
		flag1 = redundant->flags;

1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
		/*
		 * environment.data still points to ((struct
		 * env_image_redundant *)addr0)->data. If the two
		 * environments differ, or one has bad crc, force a
		 * write-out by marking the environment dirty.
		 */
		if (memcmp(environment.data, redundant->data, ENV_SIZE) ||
		    !crc0_ok || !crc1_ok)
			environment.dirty = 1;

G
Guennadi Liakhovetski 已提交
1513 1514 1515 1516 1517
		if (crc0_ok && !crc1_ok) {
			dev_current = 0;
		} else if (!crc0_ok && crc1_ok) {
			dev_current = 1;
		} else if (!crc0_ok && !crc1_ok) {
A
Alex Kiernan 已提交
1518
			fprintf(stderr,
W
wdenk 已提交
1519
				"Warning: Bad CRC, using default environment\n");
A
Alex Kiernan 已提交
1520 1521
			memcpy(environment.data, default_environment,
			       sizeof(default_environment));
1522
			environment.dirty = 1;
G
Guennadi Liakhovetski 已提交
1523 1524 1525 1526
			dev_current = 0;
		} else {
			switch (environment.flag_scheme) {
			case FLAG_BOOLEAN:
S
Simon Glass 已提交
1527 1528
				if (flag0 == ENV_REDUND_ACTIVE &&
				    flag1 == ENV_REDUND_OBSOLETE) {
G
Guennadi Liakhovetski 已提交
1529
					dev_current = 0;
S
Simon Glass 已提交
1530 1531
				} else if (flag0 == ENV_REDUND_OBSOLETE &&
					   flag1 == ENV_REDUND_ACTIVE) {
G
Guennadi Liakhovetski 已提交
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
					dev_current = 1;
				} else if (flag0 == flag1) {
					dev_current = 0;
				} else if (flag0 == 0xFF) {
					dev_current = 0;
				} else if (flag1 == 0xFF) {
					dev_current = 1;
				} else {
					dev_current = 0;
				}
				break;
			case FLAG_INCREMENTAL:
1544
				if (flag0 == 255 && flag1 == 0)
G
Guennadi Liakhovetski 已提交
1545 1546
					dev_current = 1;
				else if ((flag1 == 255 && flag0 == 0) ||
1547
					 flag0 >= flag1)
G
Guennadi Liakhovetski 已提交
1548
					dev_current = 0;
A
Alex Kiernan 已提交
1549
				else	/* flag1 > flag0 */
1550
					dev_current = 1;
G
Guennadi Liakhovetski 已提交
1551 1552
				break;
			default:
A
Alex Kiernan 已提交
1553 1554
				fprintf(stderr, "Unknown flag scheme %u\n",
					environment.flag_scheme);
G
Guennadi Liakhovetski 已提交
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
				return -1;
			}
		}

		/*
		 * If we are reading, we don't need the flag and the CRC any
		 * more, if we are writing, we will re-calculate CRC and update
		 * flags before writing out
		 */
		if (dev_current) {
A
Alex Kiernan 已提交
1565 1566 1567 1568 1569
			environment.image = addr1;
			environment.crc = &redundant->crc;
			environment.flags = &redundant->flags;
			environment.data = redundant->data;
			free(addr0);
G
Guennadi Liakhovetski 已提交
1570
		} else {
A
Alex Kiernan 已提交
1571
			environment.image = addr0;
G
Guennadi Liakhovetski 已提交
1572
			/* Other pointers are already set */
A
Alex Kiernan 已提交
1573
			free(addr1);
1574
		}
J
Joe Hershberger 已提交
1575 1576 1577
#ifdef DEBUG
		fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
#endif
1578
	}
G
Guennadi Liakhovetski 已提交
1579
	return 0;
1580

A
Alex Kiernan 已提交
1581
 open_cleanup:
1582 1583 1584 1585
	if (addr0)
		free(addr0);

	if (addr1)
B
Björn Stenberg 已提交
1586
		free(addr1);
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601

	return ret;
}

/*
 * Simply free allocated buffer with environment
 */
int fw_env_close(struct env_opts *opts)
{
	if (environment.image)
		free(environment.image);

	environment.image = NULL;

	return 0;
1602 1603
}

1604 1605 1606
static int check_device_config(int dev)
{
	struct stat st;
1607
	int32_t lnum = 0;
1608 1609
	int fd, rc = 0;

1610 1611 1612
	/* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */
	ubi_check_dev(dev);

1613 1614 1615
	fd = open(DEVNAME(dev), O_RDONLY);
	if (fd < 0) {
		fprintf(stderr,
A
Alex Kiernan 已提交
1616
			"Cannot open %s: %s\n", DEVNAME(dev), strerror(errno));
1617 1618 1619 1620 1621
		return -1;
	}

	rc = fstat(fd, &st);
	if (rc < 0) {
A
Alex Kiernan 已提交
1622
		fprintf(stderr, "Cannot stat the file %s\n", DEVNAME(dev));
1623 1624 1625
		goto err;
	}

1626 1627 1628 1629 1630 1631 1632 1633
	if (IS_UBI(dev)) {
		rc = ioctl(fd, UBI_IOCEBISMAP, &lnum);
		if (rc < 0) {
			fprintf(stderr, "Cannot get UBI information for %s\n",
				DEVNAME(dev));
			goto err;
		}
	} else if (S_ISCHR(st.st_mode)) {
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
		struct mtd_info_user mtdinfo;
		rc = ioctl(fd, MEMGETINFO, &mtdinfo);
		if (rc < 0) {
			fprintf(stderr, "Cannot get MTD information for %s\n",
				DEVNAME(dev));
			goto err;
		}
		if (mtdinfo.type != MTD_NORFLASH &&
		    mtdinfo.type != MTD_NANDFLASH &&
		    mtdinfo.type != MTD_DATAFLASH &&
		    mtdinfo.type != MTD_UBIVOLUME) {
			fprintf(stderr, "Unsupported flash type %u on %s\n",
				mtdinfo.type, DEVNAME(dev));
			goto err;
		}
		DEVTYPE(dev) = mtdinfo.type;
1650 1651 1652
		if (DEVESIZE(dev) == 0 && ENVSECTORS(dev) == 0 &&
		    mtdinfo.type == MTD_NORFLASH)
			DEVESIZE(dev) = mtdinfo.erasesize;
1653 1654 1655
		if (DEVESIZE(dev) == 0)
			/* Assume the erase size is the same as the env-size */
			DEVESIZE(dev) = ENVSIZE(dev);
1656
	} else {
S
Stefan Agner 已提交
1657
		uint64_t size;
1658
		DEVTYPE(dev) = MTD_ABSENT;
1659 1660 1661
		if (DEVESIZE(dev) == 0)
			/* Assume the erase size to be 512 bytes */
			DEVESIZE(dev) = 0x200;
S
Stefan Agner 已提交
1662 1663 1664 1665 1666 1667 1668 1669

		/*
		 * Check for negative offsets, treat it as backwards offset
		 * from the end of the block device
		 */
		if (DEVOFFSET(dev) < 0) {
			rc = ioctl(fd, BLKGETSIZE64, &size);
			if (rc < 0) {
A
Alex Kiernan 已提交
1670 1671
				fprintf(stderr,
					"Could not get block device size on %s\n",
S
Stefan Agner 已提交
1672 1673 1674 1675 1676 1677
					DEVNAME(dev));
				goto err;
			}

			DEVOFFSET(dev) = DEVOFFSET(dev) + size;
#ifdef DEBUG
A
Alex Kiernan 已提交
1678 1679
			fprintf(stderr,
				"Calculated device offset 0x%llx on %s\n",
S
Stefan Agner 已提交
1680 1681 1682
				DEVOFFSET(dev), DEVNAME(dev));
#endif
		}
1683 1684
	}

1685 1686 1687 1688 1689
	if (ENVSECTORS(dev) == 0)
		/* Assume enough sectors to cover the environment */
		ENVSECTORS(dev) = DIV_ROUND_UP(ENVSIZE(dev), DEVESIZE(dev));

	if (DEVOFFSET(dev) % DEVESIZE(dev) != 0) {
A
Alex Kiernan 已提交
1690 1691
		fprintf(stderr,
			"Environment does not start on (erase) block boundary\n");
1692 1693 1694 1695 1696
		errno = EINVAL;
		return -1;
	}

	if (ENVSIZE(dev) > ENVSECTORS(dev) * DEVESIZE(dev)) {
A
Alex Kiernan 已提交
1697 1698
		fprintf(stderr,
			"Environment does not fit into available sectors\n");
1699 1700 1701 1702
		errno = EINVAL;
		return -1;
	}

A
Alex Kiernan 已提交
1703
 err:
1704 1705 1706
	close(fd);
	return rc;
}
1707

1708
static int parse_config(struct env_opts *opts)
1709
{
1710
	int rc;
1711

1712 1713
	if (!opts)
		opts = &default_opts;
1714

1715
#if defined(CONFIG_FILE)
1716
	/* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
1717
	if (get_config(opts->config_file)) {
1718
		fprintf(stderr, "Cannot parse config file '%s': %m\n",
1719
			opts->config_file);
G
Guennadi Liakhovetski 已提交
1720
		return -1;
1721
	}
1722
#else
A
Alex Kiernan 已提交
1723 1724 1725
	DEVNAME(0) = DEVICE1_NAME;
	DEVOFFSET(0) = DEVICE1_OFFSET;
	ENVSIZE(0) = ENV1_SIZE;
1726 1727 1728 1729

	/* Set defaults for DEVESIZE, ENVSECTORS later once we
	 * know DEVTYPE
	 */
1730
#ifdef DEVICE1_ESIZE
A
Alex Kiernan 已提交
1731
	DEVESIZE(0) = DEVICE1_ESIZE;
1732 1733
#endif
#ifdef DEVICE1_ENVSECTORS
A
Alex Kiernan 已提交
1734
	ENVSECTORS(0) = DEVICE1_ENVSECTORS;
1735 1736
#endif

1737
#ifdef HAVE_REDUND
A
Alex Kiernan 已提交
1738 1739 1740
	DEVNAME(1) = DEVICE2_NAME;
	DEVOFFSET(1) = DEVICE2_OFFSET;
	ENVSIZE(1) = ENV2_SIZE;
1741 1742 1743 1744

	/* Set defaults for DEVESIZE, ENVSECTORS later once we
	 * know DEVTYPE
	 */
1745
#ifdef DEVICE2_ESIZE
A
Alex Kiernan 已提交
1746
	DEVESIZE(1) = DEVICE2_ESIZE;
1747 1748
#endif
#ifdef DEVICE2_ENVSECTORS
A
Alex Kiernan 已提交
1749
	ENVSECTORS(1) = DEVICE2_ENVSECTORS;
1750
#endif
1751
	have_redund_env = 1;
1752
#endif
1753
#endif
1754 1755 1756
	rc = check_device_config(0);
	if (rc < 0)
		return rc;
W
wdenk 已提交
1757

1758
	if (have_redund_env) {
1759 1760 1761
		rc = check_device_config(1);
		if (rc < 0)
			return rc;
1762

1763 1764
		if (ENVSIZE(0) != ENVSIZE(1)) {
			fprintf(stderr,
P
Philip Molloy 已提交
1765
				"Redundant environments have unequal size\n");
1766
			return -1;
1767
		}
1768 1769 1770
	}

	usable_envsize = CUR_ENVSIZE - sizeof(uint32_t);
1771
	if (have_redund_env)
1772 1773
		usable_envsize -= sizeof(char);

1774 1775
	return 0;
}
1776 1777

#if defined(CONFIG_FILE)
A
Alex Kiernan 已提交
1778
static int get_config(char *fname)
1779 1780 1781 1782
{
	FILE *fp;
	int i = 0;
	int rc;
1783 1784
	char *line = NULL;
	size_t linesize = 0;
1785
	char *devname;
1786

A
Alex Kiernan 已提交
1787
	fp = fopen(fname, "r");
G
Guennadi Liakhovetski 已提交
1788 1789
	if (fp == NULL)
		return -1;
1790

1791 1792 1793
	while (i < 2 && getline(&line, &linesize, fp) != -1) {
		/* Skip comment strings */
		if (line[0] == '#')
1794
			continue;
G
Guennadi Liakhovetski 已提交
1795

1796
		rc = sscanf(line, "%ms %lli %lx %lx %lx",
S
Stefan Agner 已提交
1797 1798
			    &devname,
			    &DEVOFFSET(i),
A
Alex Kiernan 已提交
1799
			    &ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i));
G
Guennadi Liakhovetski 已提交
1800

1801
		if (rc < 3)
G
Guennadi Liakhovetski 已提交
1802 1803
			continue;

1804 1805
		DEVNAME(i) = devname;

1806 1807 1808
		/* Set defaults for DEVESIZE, ENVSECTORS later once we
		 * know DEVTYPE
		 */
1809 1810 1811

		i++;
	}
1812
	free(line);
A
Alex Kiernan 已提交
1813
	fclose(fp);
W
wdenk 已提交
1814

1815
	have_redund_env = i - 1;
A
Alex Kiernan 已提交
1816
	if (!i) {		/* No valid entries found */
1817
		errno = EINVAL;
G
Guennadi Liakhovetski 已提交
1818
		return -1;
1819 1820 1821 1822
	} else
		return 0;
}
#endif