fw_env.c 39.3 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);
949
		if (rc == -1) {
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
#endif
959 960 961 962 963 964 965 966 967 968 969 970
		processed += rc;
		if (rc != readlen) {
			fprintf(stderr,
				"Warning on %s: Attempted to read %zd bytes but got %d\n",
				DEVNAME(dev), readlen, rc);
			readlen -= rc;
			block_seek += rc;
		} else {
			blockstart += blocklen;
			readlen = min(blocklen, count - processed);
			block_seek = 0;
		}
G
Guennadi Liakhovetski 已提交
971 972 973 974 975 976
	}

	return processed;
}

/*
977 978
 * Write count bytes from begin of environment, but stay within
 * ENVSECTORS(dev) sectors of
979 980
 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
 * erase and write the whole data at once.
G
Guennadi Liakhovetski 已提交
981
 */
982
static int flash_write_buf(int dev, int fd, void *buf, size_t count)
G
Guennadi Liakhovetski 已提交
983 984 985 986 987 988 989 990 991
{
	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 */
992
	size_t write_total;	/* total size to actually write - excluding
G
Guennadi Liakhovetski 已提交
993 994 995 996 997 998 999
				   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 */
1000
	int was_locked = 0;	/* flash lock flag */
G
Guennadi Liakhovetski 已提交
1001 1002
	int rc;

1003 1004 1005
	/*
	 * For mtd devices only offset and size of the environment do matter
	 */
1006
	if (DEVTYPE(dev) == MTD_ABSENT) {
1007 1008
		blocklen = count;
		erase_len = blocklen;
1009
		blockstart = DEVOFFSET(dev);
1010 1011 1012 1013
		block_seek = 0;
		write_total = blocklen;
	} else {
		blocklen = DEVESIZE(dev);
G
Guennadi Liakhovetski 已提交
1014

1015
		erase_offset = DEVOFFSET(dev);
1016

1017
		/* Maximum area we may use */
1018
		erase_len = environment_end(dev) - erase_offset;
G
Guennadi Liakhovetski 已提交
1019

1020
		blockstart = erase_offset;
1021

1022
		/* Offset inside a block */
1023
		block_seek = DEVOFFSET(dev) - erase_offset;
G
Guennadi Liakhovetski 已提交
1024

1025 1026 1027 1028 1029 1030
		/*
		 * 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 已提交
1031
			       blocklen) * blocklen;
1032
	}
G
Guennadi Liakhovetski 已提交
1033 1034 1035 1036 1037 1038 1039

	/*
	 * 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 已提交
1040
		data = malloc(erase_len);
G
Guennadi Liakhovetski 已提交
1041
		if (!data) {
A
Alex Kiernan 已提交
1042 1043 1044
			fprintf(stderr,
				"Cannot malloc %zu bytes: %s\n",
				erase_len, strerror(errno));
G
Guennadi Liakhovetski 已提交
1045
			return -1;
1046
		}
G
Guennadi Liakhovetski 已提交
1047

1048
		rc = flash_read_buf(dev, fd, data, write_total, erase_offset);
G
Guennadi Liakhovetski 已提交
1049 1050 1051
		if (write_total != rc)
			return -1;

J
Joe Hershberger 已提交
1052 1053 1054 1055 1056 1057 1058
#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 ");
1059
			fprintf(stderr, "0x%lx - 0x%lx",
A
Alex Kiernan 已提交
1060 1061
				(unsigned long)block_seek + count,
				(unsigned long)write_total - 1);
J
Joe Hershberger 已提交
1062 1063 1064
		}
		fprintf(stderr, "\n");
#endif
G
Guennadi Liakhovetski 已提交
1065
		/* Overwrite the old environment */
A
Alex Kiernan 已提交
1066
		memcpy(data + block_seek, buf, count);
G
Guennadi Liakhovetski 已提交
1067 1068 1069 1070 1071 1072 1073 1074
	} else {
		/*
		 * We get here, iff offset is block-aligned and count is a
		 * multiple of blocklen - see write_total calculation above
		 */
		data = buf;
	}

1075
	if (DEVTYPE(dev) == MTD_NANDFLASH) {
G
Guennadi Liakhovetski 已提交
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
		/*
		 * 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;
1086 1087 1088 1089 1090 1091
	if (DEVTYPE(dev) != MTD_ABSENT) {
		was_locked = ioctl(fd, MEMISLOCKED, &erase);
		/* treat any errors as unlocked flash */
		if (was_locked < 0)
			was_locked = 0;
	}
G
Guennadi Liakhovetski 已提交
1092

1093
	/* This only runs once on NOR flash and SPI-dataflash */
G
Guennadi Liakhovetski 已提交
1094
	while (processed < write_total) {
1095
		rc = flash_bad_block(fd, DEVTYPE(dev), blockstart);
A
Alex Kiernan 已提交
1096
		if (rc < 0)	/* block test failed */
G
Guennadi Liakhovetski 已提交
1097 1098
			return rc;

1099
		if (blockstart + erasesize > environment_end(dev)) {
A
Alex Kiernan 已提交
1100
			fprintf(stderr, "End of range reached, aborting\n");
G
Guennadi Liakhovetski 已提交
1101
			return -1;
1102
		}
G
Guennadi Liakhovetski 已提交
1103

A
Alex Kiernan 已提交
1104
		if (rc) {	/* block is bad */
G
Guennadi Liakhovetski 已提交
1105 1106 1107 1108
			blockstart += blocklen;
			continue;
		}

1109
		if (DEVTYPE(dev) != MTD_ABSENT) {
1110
			erase.start = blockstart;
1111 1112
			if (was_locked)
				ioctl(fd, MEMUNLOCK, &erase);
1113
			/* These do not need an explicit erase cycle */
1114
			if (DEVTYPE(dev) != MTD_DATAFLASH)
1115 1116 1117 1118 1119 1120 1121
				if (ioctl(fd, MEMERASE, &erase) != 0) {
					fprintf(stderr,
						"MTD erase error on %s: %s\n",
						DEVNAME(dev), strerror(errno));
					return -1;
				}
		}
G
Guennadi Liakhovetski 已提交
1122

A
Alex Kiernan 已提交
1123 1124 1125 1126
		if (lseek(fd, blockstart, SEEK_SET) == -1) {
			fprintf(stderr,
				"Seek error on %s: %s\n",
				DEVNAME(dev), strerror(errno));
G
Guennadi Liakhovetski 已提交
1127
			return -1;
1128
		}
G
Guennadi Liakhovetski 已提交
1129
#ifdef DEBUG
1130
		fprintf(stderr, "Write 0x%llx bytes at 0x%llx\n",
A
Alex Kiernan 已提交
1131 1132
			(unsigned long long)erasesize,
			(unsigned long long)blockstart);
G
Guennadi Liakhovetski 已提交
1133
#endif
A
Alex Kiernan 已提交
1134 1135 1136
		if (write(fd, data + processed, erasesize) != erasesize) {
			fprintf(stderr, "Write error on %s: %s\n",
				DEVNAME(dev), strerror(errno));
G
Guennadi Liakhovetski 已提交
1137
			return -1;
1138
		}
G
Guennadi Liakhovetski 已提交
1139

1140 1141 1142 1143
		if (DEVTYPE(dev) != MTD_ABSENT) {
			if (was_locked)
				ioctl(fd, MEMLOCK, &erase);
		}
G
Guennadi Liakhovetski 已提交
1144

A
Alex Kiernan 已提交
1145
		processed += erasesize;
G
Guennadi Liakhovetski 已提交
1146
		block_seek = 0;
1147
		blockstart += erasesize;
G
Guennadi Liakhovetski 已提交
1148 1149 1150
	}

	if (write_total > count)
A
Alex Kiernan 已提交
1151
		free(data);
G
Guennadi Liakhovetski 已提交
1152 1153 1154 1155 1156 1157 1158

	return processed;
}

/*
 * Set obsolete flag at offset - NOR flash only
 */
A
Alex Kiernan 已提交
1159
static int flash_flag_obsolete(int dev, int fd, off_t offset)
G
Guennadi Liakhovetski 已提交
1160 1161
{
	int rc;
1162
	struct erase_info_user erase;
P
Pierre-Jean Texier 已提交
1163
	char tmp = ENV_REDUND_OBSOLETE;
1164
	int was_locked;	/* flash lock flag */
G
Guennadi Liakhovetski 已提交
1165

1166
	was_locked = ioctl(fd, MEMISLOCKED, &erase);
A
Alex Kiernan 已提交
1167 1168
	erase.start = DEVOFFSET(dev);
	erase.length = DEVESIZE(dev);
S
Simon Glass 已提交
1169
	/* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */
A
Alex Kiernan 已提交
1170
	rc = lseek(fd, offset, SEEK_SET);
G
Guennadi Liakhovetski 已提交
1171
	if (rc < 0) {
A
Alex Kiernan 已提交
1172 1173
		fprintf(stderr, "Cannot seek to set the flag on %s\n",
			DEVNAME(dev));
G
Guennadi Liakhovetski 已提交
1174 1175
		return rc;
	}
1176 1177
	if (was_locked)
		ioctl(fd, MEMUNLOCK, &erase);
P
Pierre-Jean Texier 已提交
1178
	rc = write(fd, &tmp, sizeof(tmp));
1179 1180
	if (was_locked)
		ioctl(fd, MEMLOCK, &erase);
G
Guennadi Liakhovetski 已提交
1181
	if (rc < 0)
A
Alex Kiernan 已提交
1182
		perror("Could not set obsolete flag");
G
Guennadi Liakhovetski 已提交
1183 1184 1185 1186

	return rc;
}

A
Alex Kiernan 已提交
1187
static int flash_write(int fd_current, int fd_target, int dev_target)
G
Guennadi Liakhovetski 已提交
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
{
	int rc;

	switch (environment.flag_scheme) {
	case FLAG_NONE:
		break;
	case FLAG_INCREMENTAL:
		(*environment.flags)++;
		break;
	case FLAG_BOOLEAN:
S
Simon Glass 已提交
1198
		*environment.flags = ENV_REDUND_ACTIVE;
G
Guennadi Liakhovetski 已提交
1199 1200
		break;
	default:
A
Alex Kiernan 已提交
1201 1202
		fprintf(stderr, "Unimplemented flash scheme %u\n",
			environment.flag_scheme);
G
Guennadi Liakhovetski 已提交
1203 1204 1205 1206
		return -1;
	}

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

1211 1212
	if (IS_UBI(dev_target)) {
		if (ubi_update_start(fd_target, CUR_ENVSIZE) < 0)
1213
			return -1;
1214 1215 1216
		return ubi_write(fd_target, environment.image, CUR_ENVSIZE);
	}

1217
	rc = flash_write_buf(dev_target, fd_target, environment.image,
1218
			     CUR_ENVSIZE);
G
Guennadi Liakhovetski 已提交
1219 1220 1221 1222 1223
	if (rc < 0)
		return rc;

	if (environment.flag_scheme == FLAG_BOOLEAN) {
		/* Have to set obsolete flag */
A
Alex Kiernan 已提交
1224 1225
		off_t offset = DEVOFFSET(dev_current) +
		    offsetof(struct env_image_redundant, flags);
G
Guennadi Liakhovetski 已提交
1226
#ifdef DEBUG
J
Joe Hershberger 已提交
1227
		fprintf(stderr,
S
Stefan Agner 已提交
1228
			"Setting obsolete flag in environment at 0x%llx on %s\n",
A
Alex Kiernan 已提交
1229
			DEVOFFSET(dev_current), DEVNAME(dev_current));
G
Guennadi Liakhovetski 已提交
1230
#endif
A
Alex Kiernan 已提交
1231
		flash_flag_obsolete(dev_current, fd_current, offset);
G
Guennadi Liakhovetski 已提交
1232 1233 1234 1235 1236
	}

	return 0;
}

A
Alex Kiernan 已提交
1237
static int flash_read(int fd)
G
Guennadi Liakhovetski 已提交
1238 1239 1240
{
	int rc;

1241 1242 1243 1244 1245 1246
	if (IS_UBI(dev_current)) {
		DEVTYPE(dev_current) = MTD_ABSENT;

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

1247
	rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
1248
			    DEVOFFSET(dev_current));
1249 1250
	if (rc != CUR_ENVSIZE)
		return -1;
G
Guennadi Liakhovetski 已提交
1251

1252
	return 0;
G
Guennadi Liakhovetski 已提交
1253 1254
}

1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
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;
}

1293 1294
static int flash_io_write(int fd_current)
{
1295 1296
	int fd_target = -1, rc, dev_target;
	const char *dname, *target_temp = NULL;
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310

	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 {
1311 1312 1313 1314 1315 1316 1317 1318
		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);
		}
1319
		dev_target = dev_current;
1320 1321
		if (fd_target == -1)
			fd_target = fd_current;
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
	}

	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));
	}

1332
	if (fd_current != fd_target) {
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
		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;
		}
1346

1347
		if (rc >= 0 && target_temp) {
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
			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));
		}
1374 1375 1376 1377 1378
	}
 exit:
	return rc;
}

A
Alex Kiernan 已提交
1379
static int flash_io(int mode)
G
Guennadi Liakhovetski 已提交
1380
{
1381
	int fd_current, rc;
G
Guennadi Liakhovetski 已提交
1382 1383

	/* dev_current: fd_current, erase_current */
A
Alex Kiernan 已提交
1384
	fd_current = open(DEVNAME(dev_current), mode);
G
Guennadi Liakhovetski 已提交
1385
	if (fd_current < 0) {
A
Alex Kiernan 已提交
1386 1387 1388
		fprintf(stderr,
			"Can't open %s: %s\n",
			DEVNAME(dev_current), strerror(errno));
G
Guennadi Liakhovetski 已提交
1389 1390 1391 1392
		return -1;
	}

	if (mode == O_RDWR) {
1393
		rc = flash_io_write(fd_current);
1394
	} else {
A
Alex Kiernan 已提交
1395
		rc = flash_read(fd_current);
1396 1397
	}

A
Alex Kiernan 已提交
1398 1399 1400 1401
	if (close(fd_current)) {
		fprintf(stderr,
			"I/O error on %s: %s\n",
			DEVNAME(dev_current), strerror(errno));
G
Guennadi Liakhovetski 已提交
1402
		return -1;
1403 1404
	}

G
Guennadi Liakhovetski 已提交
1405
	return rc;
1406 1407 1408 1409 1410
}

/*
 * Prevent confusion if running from erased flash memory
 */
1411
int fw_env_open(struct env_opts *opts)
1412
{
G
Guennadi Liakhovetski 已提交
1413
	int crc0, crc0_ok;
1414
	unsigned char flag0;
1415
	void *addr0 = NULL;
G
Guennadi Liakhovetski 已提交
1416

1417
	int crc1, crc1_ok;
1418
	unsigned char flag1;
1419
	void *addr1 = NULL;
1420

1421 1422
	int ret;

G
Guennadi Liakhovetski 已提交
1423 1424
	struct env_image_single *single;
	struct env_image_redundant *redundant;
1425

1426 1427 1428
	if (!opts)
		opts = &default_opts;

A
Alex Kiernan 已提交
1429
	if (parse_config(opts))	/* should fill envdevices */
1430
		return -EINVAL;
W
wdenk 已提交
1431

1432
	addr0 = calloc(1, CUR_ENVSIZE);
G
Guennadi Liakhovetski 已提交
1433
	if (addr0 == NULL) {
1434
		fprintf(stderr,
W
wdenk 已提交
1435
			"Not enough memory for environment (%ld bytes)\n",
1436
			CUR_ENVSIZE);
1437 1438
		ret = -ENOMEM;
		goto open_cleanup;
1439
	}
W
wdenk 已提交
1440

1441
	/* read environment from FLASH to local buffer */
G
Guennadi Liakhovetski 已提交
1442 1443
	environment.image = addr0;

1444
	if (have_redund_env) {
G
Guennadi Liakhovetski 已提交
1445
		redundant = addr0;
A
Alex Kiernan 已提交
1446 1447 1448
		environment.crc = &redundant->crc;
		environment.flags = &redundant->flags;
		environment.data = redundant->data;
G
Guennadi Liakhovetski 已提交
1449 1450
	} else {
		single = addr0;
A
Alex Kiernan 已提交
1451 1452 1453
		environment.crc = &single->crc;
		environment.flags = NULL;
		environment.data = single->data;
1454
	}
W
wdenk 已提交
1455

G
Guennadi Liakhovetski 已提交
1456
	dev_current = 0;
1457
	if (flash_io(O_RDONLY)) {
1458 1459 1460
		ret = -EIO;
		goto open_cleanup;
	}
G
Guennadi Liakhovetski 已提交
1461

1462 1463 1464
	crc0 = crc32(0, (uint8_t *)environment.data, ENV_SIZE);

	crc0_ok = (crc0 == *environment.crc);
1465
	if (!have_redund_env) {
G
Guennadi Liakhovetski 已提交
1466
		if (!crc0_ok) {
A
Alex Kiernan 已提交
1467
			fprintf(stderr,
W
wdenk 已提交
1468
				"Warning: Bad CRC, using default environment\n");
A
Alex Kiernan 已提交
1469 1470
			memcpy(environment.data, default_environment,
			       sizeof(default_environment));
1471
			environment.dirty = 1;
1472
		}
1473
	} else {
G
Guennadi Liakhovetski 已提交
1474
		flag0 = *environment.flags;
W
wdenk 已提交
1475

G
Guennadi Liakhovetski 已提交
1476
		dev_current = 1;
1477
		addr1 = calloc(1, CUR_ENVSIZE);
G
Guennadi Liakhovetski 已提交
1478
		if (addr1 == NULL) {
1479
			fprintf(stderr,
W
wdenk 已提交
1480
				"Not enough memory for environment (%ld bytes)\n",
1481
				CUR_ENVSIZE);
1482 1483
			ret = -ENOMEM;
			goto open_cleanup;
W
wdenk 已提交
1484
		}
G
Guennadi Liakhovetski 已提交
1485
		redundant = addr1;
W
wdenk 已提交
1486

G
Guennadi Liakhovetski 已提交
1487 1488 1489 1490 1491
		/*
		 * have to set environment.image for flash_read(), careful -
		 * other pointers in environment still point inside addr0
		 */
		environment.image = addr1;
1492
		if (flash_io(O_RDONLY)) {
1493 1494
			ret = -EIO;
			goto open_cleanup;
1495
		}
G
Guennadi Liakhovetski 已提交
1496 1497 1498 1499 1500 1501 1502 1503

		/* 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;
1504 1505 1506
		} else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
			   DEVTYPE(!dev_current) == MTD_DATAFLASH) {
			environment.flag_scheme = FLAG_BOOLEAN;
1507 1508 1509
		} else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
			   DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
			environment.flag_scheme = FLAG_INCREMENTAL;
1510
		} else if (DEVTYPE(dev_current) == MTD_ABSENT &&
1511 1512
			   DEVTYPE(!dev_current) == MTD_ABSENT &&
			   IS_UBI(dev_current) == IS_UBI(!dev_current)) {
1513
			environment.flag_scheme = FLAG_INCREMENTAL;
G
Guennadi Liakhovetski 已提交
1514
		} else {
A
Alex Kiernan 已提交
1515
			fprintf(stderr, "Incompatible flash types!\n");
1516 1517
			ret = -EINVAL;
			goto open_cleanup;
1518
		}
W
wdenk 已提交
1519

1520 1521 1522
		crc1 = crc32(0, (uint8_t *)redundant->data, ENV_SIZE);

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

1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
		/*
		 * 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 已提交
1535 1536 1537 1538 1539
		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 已提交
1540
			fprintf(stderr,
W
wdenk 已提交
1541
				"Warning: Bad CRC, using default environment\n");
A
Alex Kiernan 已提交
1542 1543
			memcpy(environment.data, default_environment,
			       sizeof(default_environment));
1544
			environment.dirty = 1;
G
Guennadi Liakhovetski 已提交
1545 1546 1547 1548
			dev_current = 0;
		} else {
			switch (environment.flag_scheme) {
			case FLAG_BOOLEAN:
S
Simon Glass 已提交
1549 1550
				if (flag0 == ENV_REDUND_ACTIVE &&
				    flag1 == ENV_REDUND_OBSOLETE) {
G
Guennadi Liakhovetski 已提交
1551
					dev_current = 0;
S
Simon Glass 已提交
1552 1553
				} else if (flag0 == ENV_REDUND_OBSOLETE &&
					   flag1 == ENV_REDUND_ACTIVE) {
G
Guennadi Liakhovetski 已提交
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
					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:
1566
				if (flag0 == 255 && flag1 == 0)
G
Guennadi Liakhovetski 已提交
1567 1568
					dev_current = 1;
				else if ((flag1 == 255 && flag0 == 0) ||
1569
					 flag0 >= flag1)
G
Guennadi Liakhovetski 已提交
1570
					dev_current = 0;
A
Alex Kiernan 已提交
1571
				else	/* flag1 > flag0 */
1572
					dev_current = 1;
G
Guennadi Liakhovetski 已提交
1573 1574
				break;
			default:
A
Alex Kiernan 已提交
1575 1576
				fprintf(stderr, "Unknown flag scheme %u\n",
					environment.flag_scheme);
G
Guennadi Liakhovetski 已提交
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
				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 已提交
1587 1588 1589 1590 1591
			environment.image = addr1;
			environment.crc = &redundant->crc;
			environment.flags = &redundant->flags;
			environment.data = redundant->data;
			free(addr0);
G
Guennadi Liakhovetski 已提交
1592
		} else {
A
Alex Kiernan 已提交
1593
			environment.image = addr0;
G
Guennadi Liakhovetski 已提交
1594
			/* Other pointers are already set */
A
Alex Kiernan 已提交
1595
			free(addr1);
1596
		}
J
Joe Hershberger 已提交
1597 1598 1599
#ifdef DEBUG
		fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
#endif
1600
	}
G
Guennadi Liakhovetski 已提交
1601
	return 0;
1602

A
Alex Kiernan 已提交
1603
 open_cleanup:
1604 1605 1606 1607
	if (addr0)
		free(addr0);

	if (addr1)
B
Björn Stenberg 已提交
1608
		free(addr1);
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623

	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;
1624 1625
}

1626 1627 1628
static int check_device_config(int dev)
{
	struct stat st;
1629
	int32_t lnum = 0;
1630 1631
	int fd, rc = 0;

1632 1633 1634
	/* Fills in IS_UBI(), converts DEVNAME() with ubi volume name */
	ubi_check_dev(dev);

1635 1636 1637
	fd = open(DEVNAME(dev), O_RDONLY);
	if (fd < 0) {
		fprintf(stderr,
A
Alex Kiernan 已提交
1638
			"Cannot open %s: %s\n", DEVNAME(dev), strerror(errno));
1639 1640 1641 1642 1643
		return -1;
	}

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

1648 1649 1650 1651 1652 1653 1654 1655
	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)) {
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
		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;
1672 1673 1674
		if (DEVESIZE(dev) == 0 && ENVSECTORS(dev) == 0 &&
		    mtdinfo.type == MTD_NORFLASH)
			DEVESIZE(dev) = mtdinfo.erasesize;
1675 1676 1677
		if (DEVESIZE(dev) == 0)
			/* Assume the erase size is the same as the env-size */
			DEVESIZE(dev) = ENVSIZE(dev);
1678
	} else {
S
Stefan Agner 已提交
1679
		uint64_t size;
1680
		DEVTYPE(dev) = MTD_ABSENT;
1681 1682 1683
		if (DEVESIZE(dev) == 0)
			/* Assume the erase size to be 512 bytes */
			DEVESIZE(dev) = 0x200;
S
Stefan Agner 已提交
1684 1685 1686 1687 1688 1689 1690 1691

		/*
		 * 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 已提交
1692 1693
				fprintf(stderr,
					"Could not get block device size on %s\n",
S
Stefan Agner 已提交
1694 1695 1696 1697 1698 1699
					DEVNAME(dev));
				goto err;
			}

			DEVOFFSET(dev) = DEVOFFSET(dev) + size;
#ifdef DEBUG
A
Alex Kiernan 已提交
1700 1701
			fprintf(stderr,
				"Calculated device offset 0x%llx on %s\n",
S
Stefan Agner 已提交
1702 1703 1704
				DEVOFFSET(dev), DEVNAME(dev));
#endif
		}
1705 1706
	}

1707 1708 1709 1710 1711
	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 已提交
1712 1713
		fprintf(stderr,
			"Environment does not start on (erase) block boundary\n");
1714 1715 1716 1717 1718
		errno = EINVAL;
		return -1;
	}

	if (ENVSIZE(dev) > ENVSECTORS(dev) * DEVESIZE(dev)) {
A
Alex Kiernan 已提交
1719 1720
		fprintf(stderr,
			"Environment does not fit into available sectors\n");
1721 1722 1723 1724
		errno = EINVAL;
		return -1;
	}

A
Alex Kiernan 已提交
1725
 err:
1726 1727 1728
	close(fd);
	return rc;
}
1729

1730
static int parse_config(struct env_opts *opts)
1731
{
1732
	int rc;
1733

1734 1735
	if (!opts)
		opts = &default_opts;
1736

1737
#if defined(CONFIG_FILE)
1738
	/* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
1739
	if (get_config(opts->config_file)) {
1740
		fprintf(stderr, "Cannot parse config file '%s': %m\n",
1741
			opts->config_file);
G
Guennadi Liakhovetski 已提交
1742
		return -1;
1743
	}
1744
#else
A
Alex Kiernan 已提交
1745 1746 1747
	DEVNAME(0) = DEVICE1_NAME;
	DEVOFFSET(0) = DEVICE1_OFFSET;
	ENVSIZE(0) = ENV1_SIZE;
1748 1749 1750 1751

	/* Set defaults for DEVESIZE, ENVSECTORS later once we
	 * know DEVTYPE
	 */
1752
#ifdef DEVICE1_ESIZE
A
Alex Kiernan 已提交
1753
	DEVESIZE(0) = DEVICE1_ESIZE;
1754 1755
#endif
#ifdef DEVICE1_ENVSECTORS
A
Alex Kiernan 已提交
1756
	ENVSECTORS(0) = DEVICE1_ENVSECTORS;
1757 1758
#endif

1759
#ifdef HAVE_REDUND
A
Alex Kiernan 已提交
1760 1761 1762
	DEVNAME(1) = DEVICE2_NAME;
	DEVOFFSET(1) = DEVICE2_OFFSET;
	ENVSIZE(1) = ENV2_SIZE;
1763 1764 1765 1766

	/* Set defaults for DEVESIZE, ENVSECTORS later once we
	 * know DEVTYPE
	 */
1767
#ifdef DEVICE2_ESIZE
A
Alex Kiernan 已提交
1768
	DEVESIZE(1) = DEVICE2_ESIZE;
1769 1770
#endif
#ifdef DEVICE2_ENVSECTORS
A
Alex Kiernan 已提交
1771
	ENVSECTORS(1) = DEVICE2_ENVSECTORS;
1772
#endif
1773
	have_redund_env = 1;
1774
#endif
1775
#endif
1776 1777 1778
	rc = check_device_config(0);
	if (rc < 0)
		return rc;
W
wdenk 已提交
1779

1780
	if (have_redund_env) {
1781 1782 1783
		rc = check_device_config(1);
		if (rc < 0)
			return rc;
1784

1785 1786
		if (ENVSIZE(0) != ENVSIZE(1)) {
			fprintf(stderr,
P
Philip Molloy 已提交
1787
				"Redundant environments have unequal size\n");
1788
			return -1;
1789
		}
1790 1791 1792
	}

	usable_envsize = CUR_ENVSIZE - sizeof(uint32_t);
1793
	if (have_redund_env)
1794 1795
		usable_envsize -= sizeof(char);

1796 1797
	return 0;
}
1798 1799

#if defined(CONFIG_FILE)
A
Alex Kiernan 已提交
1800
static int get_config(char *fname)
1801 1802 1803 1804
{
	FILE *fp;
	int i = 0;
	int rc;
1805 1806
	char *line = NULL;
	size_t linesize = 0;
1807
	char *devname;
1808

A
Alex Kiernan 已提交
1809
	fp = fopen(fname, "r");
G
Guennadi Liakhovetski 已提交
1810 1811
	if (fp == NULL)
		return -1;
1812

1813 1814 1815
	while (i < 2 && getline(&line, &linesize, fp) != -1) {
		/* Skip comment strings */
		if (line[0] == '#')
1816
			continue;
G
Guennadi Liakhovetski 已提交
1817

1818
		rc = sscanf(line, "%ms %lli %lx %lx %lx",
S
Stefan Agner 已提交
1819 1820
			    &devname,
			    &DEVOFFSET(i),
A
Alex Kiernan 已提交
1821
			    &ENVSIZE(i), &DEVESIZE(i), &ENVSECTORS(i));
G
Guennadi Liakhovetski 已提交
1822

1823
		if (rc < 3)
G
Guennadi Liakhovetski 已提交
1824 1825
			continue;

1826 1827
		DEVNAME(i) = devname;

1828 1829 1830
		/* Set defaults for DEVESIZE, ENVSECTORS later once we
		 * know DEVTYPE
		 */
1831 1832 1833

		i++;
	}
1834
	free(line);
A
Alex Kiernan 已提交
1835
	fclose(fp);
W
wdenk 已提交
1836

1837
	have_redund_env = i - 1;
A
Alex Kiernan 已提交
1838
	if (!i) {		/* No valid entries found */
1839
		errno = EINVAL;
G
Guennadi Liakhovetski 已提交
1840
		return -1;
1841 1842 1843 1844
	} else
		return 0;
}
#endif