aboutsummaryrefslogtreecommitdiff
path: root/external
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2020-06-09 14:40:51 +1000
committerOliver O'Halloran <oohal@users.noreply.github.com>2020-06-11 10:22:43 +1000
commitcfd6168cdd763d722fa7327317ea643c3422bb5c (patch)
tree9a5b5ad92490489b25c3ab7ec391a9ec62f69b3e /external
parent3da602776f445f50488d9407661f1addd1eac180 (diff)
downloadskiboot-cfd6168cdd763d722fa7327317ea643c3422bb5c.zip
skiboot-cfd6168cdd763d722fa7327317ea643c3422bb5c.tar.gz
skiboot-cfd6168cdd763d722fa7327317ea643c3422bb5c.tar.bz2
external/ffspart: Use read() rather than mmap()
The various ffspart test cases use /dev/zero as an input which doesn't behave like a normal file. The stat.st_size field for char devs is generally zero so the subsequent attempt to mmap() the file fails because we requested a zero size mapping. Previously we didn't notice this, but it sort of worked since the partitions in the test script that used /dev/zero as an input were also had those partitions marked as ECC. This resulted in the partition contents being re-generated (using a buffer libflash allocates) and the source data pointer being ignored since we said it was zero length. Fix all this by dropping mmap() entirely and inhale the input file into a buffer we malloc() instead. This works for any file, including /dev/urandom, which can't be mmap()ed. Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Diffstat (limited to 'external')
-rw-r--r--external/ffspart/ffspart.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/external/ffspart/ffspart.c b/external/ffspart/ffspart.c
index d41bdfd..98e790b 100644
--- a/external/ffspart/ffspart.c
+++ b/external/ffspart/ffspart.c
@@ -241,6 +241,8 @@ static int parse_entry(struct blocklevel_device *bl,
ffs_entry_put(new_entry);
if (*line != '\0' && *(line + 1) != '\0') {
+ size_t data_len;
+
filename = line + 1;
/*
@@ -263,9 +265,30 @@ static int parse_entry(struct blocklevel_device *bl,
close(data_fd);
return -1;
}
+
+ data_ptr = calloc(1, psize);
+ if (!data_ptr) {
+ return -1;
+ }
+
pactual = data_stat.st_size;
/*
+ * There's two char device inputs we care about: /dev/zero and
+ * /dev/urandom. Both have a stat.st_size of zero so read in
+ * a full partition worth, accounting for ECC overhead.
+ */
+ if (!pactual && S_ISCHR(data_stat.st_mode)) {
+ pactual = psize;
+
+ if (has_ecc(new_entry)) {
+ pactual = ecc_buffer_size_minus_ecc(pactual);
+
+ /* ECC input size needs to be a multiple of 8 */
+ pactual = pactual & ~0x7;
+ }
+ }
+ /*
* Sanity check that the file isn't too large for
* partition
*/
@@ -279,19 +302,22 @@ static int parse_entry(struct blocklevel_device *bl,
return -1;
}
- data_ptr = mmap(NULL, pactual, PROT_READ, MAP_SHARED, data_fd, 0);
- if (!data_ptr) {
- fprintf(stderr, "Couldn't mmap file '%s' for '%s' partition "
- "(%m)\n", filename, name);
- close(data_fd);
- return -1;
+ for (data_len = 0; data_len < pactual; data_len += rc) {
+ rc = read(data_fd, &data_ptr[data_len], pactual - data_len);
+ if (rc == -1) {
+ fprintf(stderr, "error reading from '%s'", filename);
+ exit(1);
+ }
}
rc = blocklevel_write(bl, pbase, data_ptr, pactual);
- if (rc)
+ if (rc) {
fprintf(stderr, "Couldn't write file '%s' for '%s' partition to PNOR "
"(%m)\n", filename, name);
- munmap(data_ptr, pactual);
+ exit(1);
+ }
+
+ free(data_ptr);
close(data_fd);
} else {
if (!allow_empty) {