load_ramdisk_fd: improved IO error handling
- while loop terminates on read error **without** resetting `seems_ok` to 0, thus read errors won't be noticed - no check if bytes_read matches the expected image size - ram_fd is leaked on write error - short writes are treated as errors (when in fact they are perfectly fine) Therefore: - Handle *all* read errors, not just the very first one - If the image size is known in advance verify if we actually read the whole image - close `ram_fd` in error code paths - Handle short writes properly Closes: #40803
This commit is contained in:
parent
dc87263d47
commit
63008e11b2
75
tools.c
75
tools.c
@ -294,15 +294,63 @@ static void save_stuff_for_rescue(void)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief copy exactly len bytes from buffer to file descriptor
|
||||
*/
|
||||
static int write_exactly(int fd, const char *buf, size_t len)
|
||||
{
|
||||
ssize_t dl;
|
||||
while (len > 0) {
|
||||
dl = write(fd, buf, len);
|
||||
if (dl < 0) {
|
||||
log_message("%s: write: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
buf += (size_t)dl;
|
||||
len -= (size_t)dl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Copy size bytes from src_fd to dst_fd
|
||||
* @param exact if non-zero check if exactly size bytes have been copied
|
||||
* @return 0 on success, -1 on error
|
||||
* @note if size == 0 keep copying until EOF on src_fd
|
||||
*/
|
||||
static int copy_loop(int dst_fd, int src_fd, unsigned long size)
|
||||
{
|
||||
char buf[32768];
|
||||
unsigned long bytes_written = 0;
|
||||
ssize_t dl;
|
||||
for (;;) {
|
||||
dl = read(src_fd, buf, sizeof(buf));
|
||||
if (dl < 0) {
|
||||
log_message("%s: read: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
} else if (dl == 0) {
|
||||
break;
|
||||
}
|
||||
if (write_exactly(dst_fd, buf, (size_t)dl) < 0) {
|
||||
return -1;
|
||||
}
|
||||
bytes_written += (size_t)dl;
|
||||
update_progression((int)BYTES2MB(bytes_written));
|
||||
}
|
||||
if (size > 0 && bytes_written != size) {
|
||||
log_message("%s: expected %lu bytes, copied %lu instead\n",
|
||||
__func__, size, bytes_written);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
||||
{
|
||||
char * ramdisk = "/dev/ram3"; /* warning, verify that this file exists in the initrd, and that root=/dev/ram3 is actually passed to the kernel at boot time */
|
||||
int ram_fd;
|
||||
char buffer[32768];
|
||||
char * wait_msg = "Loading program into memory...";
|
||||
unsigned long bytes_read = 0;
|
||||
ssize_t actually;
|
||||
int seems_ok = 0;
|
||||
|
||||
ram_fd = open(ramdisk, O_WRONLY);
|
||||
if (ram_fd == -1) {
|
||||
@ -312,22 +360,8 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
||||
}
|
||||
|
||||
init_progression(wait_msg, (int)BYTES2MB(size));
|
||||
|
||||
while ((actually = read(source_fd, buffer, sizeof(buffer))) > 0) {
|
||||
seems_ok = 1;
|
||||
if (write(ram_fd, buffer, actually) != actually) {
|
||||
log_perror("writing ramdisk");
|
||||
remove_wait_message();
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
bytes_read += actually;
|
||||
update_progression((int)BYTES2MB(bytes_read));
|
||||
if (bytes_read == size)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!seems_ok) {
|
||||
log_message("reading compressed ramdisk: %s", strerror(errno));
|
||||
if (copy_loop(ram_fd, source_fd, size) < 0) {
|
||||
log_message("%s: failed to load image to RAM", __func__);
|
||||
close(ram_fd);
|
||||
remove_wait_message();
|
||||
stg1_error_message("Could not load second stage ramdisk. "
|
||||
@ -335,7 +369,6 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size)
|
||||
"(this may be caused by a hardware failure or a Linux kernel bug)");
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
end_progression();
|
||||
|
||||
close(ram_fd);
|
||||
|
Loading…
Reference in New Issue
Block a user