diff --git a/tools.c b/tools.c index 3b059be..67723c0 100644 --- a/tools.c +++ b/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);