From 36b688d17aa33716f1ddf8b15660fda61cc03523 Mon Sep 17 00:00:00 2001 From: Alexey Sheplyakov Date: Sun, 8 Aug 2021 14:03:54 +0400 Subject: [PATCH] network boot: support loading complete ISOs via HTTP Now I don't have to unpack (or loop mount) ISO to boot via HTTP. Also I can boot directly from any ALT mirror, like this: automatic=method:http,network:dhcp,server:mirror.yandex.ru,directory=/altlinux/images/p9/simply/aarch64/slinux-live-9.1.1-aarch64.iso Closes: #40710 --- config-stage1.h | 1 + lomount.c | 2 +- network.c | 11 +++++++- tools.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++- tools.h | 1 + 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/config-stage1.h b/config-stage1.h index 5258785..7dfbc38 100644 --- a/config-stage1.h +++ b/config-stage1.h @@ -23,6 +23,7 @@ #define IMAGE_LOCATION "/image" #define STAGE2_LOCATION "/root" #define LIVE_DEVICE "/dev/loop0" +#define LOMOUNT_DEVICE "/dev/loop3" #define STAGE2FS "squashfs" #define LIVEFS "squashfs" #ifndef STAGE2_BINNAME diff --git a/lomount.c b/lomount.c index b39caf3..26a8bf1 100644 --- a/lomount.c +++ b/lomount.c @@ -133,7 +133,7 @@ set_loop (const char *device, const char *file) } -char * loopdev = "/dev/loop3"; /* Ugly. But do I care? */ +char * loopdev = LOMOUNT_DEVICE; /* Ugly. But do I care? */ void del_loop(char *device) { diff --git a/network.c b/network.c index 1e7755a..29c6aed 100644 --- a/network.c +++ b/network.c @@ -998,6 +998,7 @@ enum return_type http_prepare(void) char *tmp; int fd; unsigned long size; + int is_iso = 0; snprintf(location_full, sizeof(location_full), "Please enter the name or IP address of the HTTP server, " @@ -1009,6 +1010,13 @@ enum return_type http_prepare(void) } strcpy(location_full, answers[1]); + log_message("HTTP: trying to retrieve %s", location_full); + fd = http_download_file(answers[0], location_full, &size); + if (fd >= 0) { + is_iso = 1; + goto download; + } + tmp = get_ramdisk_realname(); strcat(location_full, tmp); free(tmp); @@ -1026,6 +1034,7 @@ enum return_type http_prepare(void) continue; } + download: if (!ramdisk_possible(size)) { close(fd); stg1_error_message("HTTP install needs more than %u Mbytes of memory (detected %u Mbytes).", @@ -1035,7 +1044,7 @@ enum return_type http_prepare(void) log_message("HTTP: size of download %lu bytes", size); - results = load_ramdisk_fd(fd, size); + results = load_ramdisk_or_iso(fd, size, is_iso); close(fd); if (results != RETURN_OK) return RETURN_ERROR; diff --git a/tools.c b/tools.c index 1a10d78..93f8b35 100644 --- a/tools.c +++ b/tools.c @@ -45,6 +45,7 @@ #include "automatic.h" #include #include +#include "lomount.h" #include "tools.h" #include "modules.h" #include "sha256.h" @@ -297,6 +298,45 @@ static void save_stuff_for_rescue(void) log_message("saved file %s for rescue (%d bytes)", file, i); } +/** + * Loop mount ISO loaded to RAM, and open stage2 + * + * @param ram_fd file descriptor of ISO image + * @return file descriptor of stage2 or -1 on error + */ +static int open_stage2_from_iso(int iso_fd) +{ + int stage2_fd = -1; + const char *stage2 = get_ramdisk_path(IMAGE_LOCATION); /* /image/live */ + if (!stage2) { + log_message("%s: get_ramdisk_size: got NULL", __func__); + goto out; + } + if (do_losetup_fd(LOMOUNT_DEVICE, iso_fd, NULL) < 0) { + log_message("%s: could not setup loopback for iso_fd", __func__); + goto out_free; + } + if (my_mount(LOMOUNT_DEVICE, IMAGE_LOCATION, "iso9660", 0)) { + log_message("%s: failed to mount ISO loopback", __func__); + goto out_del_loop; + } + stage2_fd = open(stage2, O_RDONLY); + if (stage2_fd < 0) { + log_message("%s: failed to open %s", __func__, stage2); + goto out_umount; + } + free((char *)stage2); + return stage2_fd; + +out_umount: + umount(IMAGE_LOCATION); +out_del_loop: + del_loop(LOMOUNT_DEVICE); +out_free: + free((char *)stage2); +out: + return -1; +} /** * @brief copy exactly len bytes from buffer to file descriptor @@ -382,7 +422,7 @@ out: return -1; } -enum return_type load_ramdisk_fd(int source_fd, unsigned long size) +enum return_type load_ramdisk_or_iso(int source_fd, unsigned long size, int is_iso) { int ram_fd; char * wait_msg = "Loading program into memory..."; @@ -405,8 +445,26 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size) } end_progression(); + if (is_iso) { + int stage2_fd = open_stage2_from_iso(ram_fd); + if (stage2_fd < 0) { + close(ram_fd); + stg1_error_message("Could not open stage2 from ISO in RAM"); + return RETURN_ERROR; + } + /* got a (mounted) loopback device backed by ram_fd, + * ram_fd itself is not necessary any more */ + close(ram_fd); + /* to setup loopback device from stage2_fd */ + ram_fd = stage2_fd; + } + if (do_losetup_fd(LIVE_DEVICE, ram_fd, NULL) < 0) { close(ram_fd); + if (is_iso) { + umount(IMAGE_LOCATION); + del_loop(LOMOUNT_DEVICE); + } stg1_error_message("Could not setup loopback for 2nd stage"); return RETURN_ERROR; } @@ -416,6 +474,10 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size) if (my_mount(LIVE_DEVICE, STAGE2_LOCATION, STAGE2FS, 0)) { stg1_error_message("Failed to mount stage2"); + if (is_iso) { + umount(IMAGE_LOCATION); + del_loop(LOMOUNT_DEVICE); + } return RETURN_ERROR; } @@ -427,12 +489,18 @@ enum return_type load_ramdisk_fd(int source_fd, unsigned long size) log_message("rescue: failed to umount " STAGE2_LOCATION); return RETURN_ERROR; } + if (is_iso) { + /* XXX: should I do anything special here? */ + } return RETURN_OK; /* fucksike, I lost several hours wondering why the kernel won't see the rescue if it is alreay mounted */ } return RETURN_OK; } +enum return_type load_ramdisk_fd(int source_fd, unsigned long size) { + return load_ramdisk_or_iso(source_fd, size, 0); +} int splash_verbose() { diff --git a/tools.h b/tools.h index 2f414d6..49cb367 100644 --- a/tools.h +++ b/tools.h @@ -36,6 +36,7 @@ int ramdisk_possible(unsigned long ramdisk_size); char * get_ramdisk_realname(void); enum return_type load_ramdisk(char *, unsigned long size); enum return_type load_ramdisk_fd(int ramdisk_fd, unsigned long size); +enum return_type load_ramdisk_or_iso(int ramdisk_fd, unsigned long size, int is_iso); void * memdup(void *src, size_t size); void add_to_env(char * name, char * value); void handle_env(char ** env);