Newer
Older
environment.flag_scheme);
return -1;
}
#ifdef DEBUG
fprintf(stderr, "Writing new environment at 0x%llx on %s\n",
DEVOFFSET (dev_target), DEVNAME (dev_target));
#endif
rc = flash_write_buf(dev_target, fd_target, environment.image,
CUR_ENVSIZE);
if (rc < 0)
return rc;
if (environment.flag_scheme == FLAG_BOOLEAN) {
/* Have to set obsolete flag */
off_t offset = DEVOFFSET (dev_current) +
offsetof (struct env_image_redundant, flags);
#ifdef DEBUG
"Setting obsolete flag in environment at 0x%llx on %s\n",
DEVOFFSET (dev_current), DEVNAME (dev_current));
#endif
flash_flag_obsolete (dev_current, fd_current, offset);
}
return 0;
}
static int flash_read (int fd)
{
int rc;
rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
DEVOFFSET(dev_current));
if (rc != CUR_ENVSIZE)
return -1;
}
static int flash_io (int mode)
{
int fd_current, fd_target, rc, dev_target;
/* dev_current: fd_current, erase_current */
fd_current = open (DEVNAME (dev_current), mode);
if (fd_current < 0) {
fprintf (stderr,
"Can't open %s: %s\n",
DEVNAME (dev_current), strerror (errno));
return -1;
}
if (mode == O_RDWR) {
if (HaveRedundEnv) {
/* switch to next partition for writing */
dev_target = !dev_current;
/* dev_target: fd_target, erase_target */
fd_target = open (DEVNAME (dev_target), mode);
if (fd_target < 0) {
fprintf (stderr,
"Can't open %s: %s\n",
DEVNAME (dev_target),
strerror (errno));
rc = -1;
goto exit;
} else {
dev_target = dev_current;
fd_target = fd_current;
rc = flash_write (fd_current, fd_target, dev_target);
if (HaveRedundEnv) {
fprintf (stderr,
}
} else {
fprintf (stderr,
"I/O error on %s: %s\n",
DEVNAME (dev_current), strerror (errno));
return -1;
}
/*
* Prevent confusion if running from erased flash memory
*/
int fw_env_open(struct env_opts *opts)
int crc1, crc1_ok;
struct env_image_single *single;
struct env_image_redundant *redundant;
if (!opts)
opts = &default_opts;
if (parse_config(opts)) /* should fill envdevices */
addr0 = calloc(1, CUR_ENVSIZE);
"Not enough memory for environment (%ld bytes)\n",
/* read environment from FLASH to local buffer */
environment.image = addr0;
if (HaveRedundEnv) {
redundant = addr0;
environment.crc = &redundant->crc;
environment.flags = &redundant->flags;
environment.data = redundant->data;
} else {
single = addr0;
environment.crc = &single->crc;
environment.flags = NULL;
environment.data = single->data;
dev_current = 0;
if (flash_io (O_RDONLY))
return -1;
crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
if (opts->aes_flag) {
ret = env_aes_cbc_crypt(environment.data, 0,
opts->aes_key);
if (ret)
return ret;
}
if (!HaveRedundEnv) {
fprintf (stderr,
"Warning: Bad CRC, using default environment\n");
memcpy(environment.data, default_environment, sizeof default_environment);
addr1 = calloc(1, CUR_ENVSIZE);
"Not enough memory for environment (%ld bytes)\n",
/*
* have to set environment.image for flash_read(), careful -
* other pointers in environment still point inside addr0
*/
environment.image = addr1;
if (flash_io (O_RDONLY))
return -1;
/* 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;
} else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
DEVTYPE(!dev_current) == MTD_DATAFLASH) {
environment.flag_scheme = FLAG_BOOLEAN;
} else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
environment.flag_scheme = FLAG_INCREMENTAL;
} else if (DEVTYPE(dev_current) == MTD_ABSENT &&
DEVTYPE(!dev_current) == MTD_ABSENT) {
environment.flag_scheme = FLAG_INCREMENTAL;
} else {
fprintf (stderr, "Incompatible flash types!\n");
return -1;
crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
if (opts->aes_flag) {
ret = env_aes_cbc_crypt(redundant->data, 0,
opts->aes_key);
if (ret)
return ret;
}
crc1_ok = (crc1 == redundant->crc);
flag1 = redundant->flags;
if (crc0_ok && !crc1_ok) {
dev_current = 0;
} else if (!crc0_ok && crc1_ok) {
dev_current = 1;
} else if (!crc0_ok && !crc1_ok) {
fprintf (stderr,
"Warning: Bad CRC, using default environment\n");
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
memcpy (environment.data, default_environment,
sizeof default_environment);
dev_current = 0;
} else {
switch (environment.flag_scheme) {
case FLAG_BOOLEAN:
if (flag0 == active_flag &&
flag1 == obsolete_flag) {
dev_current = 0;
} else if (flag0 == obsolete_flag &&
flag1 == active_flag) {
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:
if (flag0 == 255 && flag1 == 0)
dev_current = 1;
else if ((flag1 == 255 && flag0 == 0) ||
else /* flag1 > flag0 */
dev_current = 1;
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
break;
default:
fprintf (stderr, "Unknown flag scheme %u \n",
environment.flag_scheme);
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) {
environment.image = addr1;
environment.crc = &redundant->crc;
environment.flags = &redundant->flags;
environment.data = redundant->data;
free (addr0);
} else {
environment.image = addr0;
/* Other pointers are already set */
#ifdef DEBUG
fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
#endif
static int check_device_config(int dev)
{
struct stat st;
int fd, rc = 0;
if (DEVOFFSET(dev) % DEVESIZE(dev) != 0) {
fprintf(stderr, "Environment does not start on (erase) block boundary\n");
errno = EINVAL;
return -1;
}
if (ENVSIZE(dev) > ENVSECTORS(dev) * DEVESIZE(dev)) {
fprintf(stderr, "Environment does not fit into available sectors\n");
errno = EINVAL;
return -1;
}
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
fd = open(DEVNAME(dev), O_RDONLY);
if (fd < 0) {
fprintf(stderr,
"Cannot open %s: %s\n",
DEVNAME(dev), strerror(errno));
return -1;
}
rc = fstat(fd, &st);
if (rc < 0) {
fprintf(stderr, "Cannot stat the file %s\n",
DEVNAME(dev));
goto err;
}
if (S_ISCHR(st.st_mode)) {
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;
} else {
DEVTYPE(dev) = MTD_ABSENT;
/*
* 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) {
fprintf(stderr, "Could not get block device size on %s\n",
DEVNAME(dev));
goto err;
}
DEVOFFSET(dev) = DEVOFFSET(dev) + size;
#ifdef DEBUG
fprintf(stderr, "Calculated device offset 0x%llx on %s\n",
DEVOFFSET(dev), DEVNAME(dev));
#endif
}
}
err:
close(fd);
return rc;
}
static int parse_config(struct env_opts *opts)
if (!opts)
opts = &default_opts;
#if defined(CONFIG_FILE)
/* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
if (get_config(opts->config_file)) {
fprintf(stderr, "Cannot parse config file '%s': %m\n",
opts->config_file);
DEVNAME (0) = DEVICE1_NAME;
DEVOFFSET (0) = DEVICE1_OFFSET;
ENVSIZE (0) = ENV1_SIZE;
/* Default values are: erase-size=env-size */
DEVESIZE (0) = ENVSIZE (0);
/* #sectors=env-size/erase-size (rounded up) */
ENVSECTORS (0) = (ENVSIZE(0) + DEVESIZE(0) - 1) / DEVESIZE(0);
#ifdef DEVICE1_ESIZE
#endif
#ifdef DEVICE1_ENVSECTORS
#endif
#ifdef HAVE_REDUND
DEVNAME (1) = DEVICE2_NAME;
DEVOFFSET (1) = DEVICE2_OFFSET;
ENVSIZE (1) = ENV2_SIZE;
/* Default values are: erase-size=env-size */
DEVESIZE (1) = ENVSIZE (1);
/* #sectors=env-size/erase-size (rounded up) */
ENVSECTORS (1) = (ENVSIZE(1) + DEVESIZE(1) - 1) / DEVESIZE(1);
#ifdef DEVICE2_ESIZE
#endif
#ifdef DEVICE2_ENVSECTORS
HaveRedundEnv = 1;
rc = check_device_config(0);
if (rc < 0)
return rc;
if (HaveRedundEnv) {
rc = check_device_config(1);
if (rc < 0)
return rc;
if (ENVSIZE(0) != ENVSIZE(1)) {
fprintf(stderr,
"Redundant environments have unequal size");
return -1;
}
usable_envsize = CUR_ENVSIZE - sizeof(uint32_t);
if (HaveRedundEnv)
usable_envsize -= sizeof(char);
if (opts->aes_flag)
usable_envsize &= ~(AES_KEY_LENGTH - 1);
return 0;
}
#if defined(CONFIG_FILE)
static int get_config (char *fname)
{
FILE *fp;
int i = 0;
int rc;
char dump[128];
fp = fopen (fname, "r");
if (fp == NULL)
return -1;
while (i < 2 && fgets (dump, sizeof (dump), fp)) {
/* Skip incomplete conversions and comment strings */
rc = sscanf(dump, "%ms %lli %lx %lx %lx",
&devname,
&DEVOFFSET(i),
&ENVSIZE(i),
&DEVESIZE(i),
&ENVSECTORS(i));
if (rc < 3)
DEVNAME(i) = devname;
if (rc < 4)
/* Assume the erase size is the same as the env-size */
DEVESIZE(i) = ENVSIZE(i);
/* Assume enough env sectors to cover the environment */
ENVSECTORS (i) = (ENVSIZE(i) + DEVESIZE(i) - 1) / DEVESIZE(i);
i++;
}
HaveRedundEnv = i - 1;
if (!i) { /* No valid entries found */
} else
return 0;
}
#endif