From 5d0ebf4510594180cedf2e1879ab2117863d7626 Mon Sep 17 00:00:00 2001 From: longpanda Date: Tue, 27 Jul 2021 19:08:40 +0800 Subject: [PATCH] support custom arch iso (#1021) --- .../grub-2.04/grub-core/disk/loopback.c | 257 ++++++++++++++++++ .../grub-2.04/grub-core/ventoy/ventoy_cmd.c | 207 ++++++++++++++ .../grub-2.04/grub-core/ventoy/ventoy_def.h | 11 + INSTALL/grub/grub.cfg | 22 ++ 4 files changed, 497 insertions(+) create mode 100644 GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c new file mode 100644 index 00000000..ef946a49 --- /dev/null +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c @@ -0,0 +1,257 @@ +/* loopback.c - command to add loopback devices. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_loopback +{ + char *devname; + grub_file_t file; + struct grub_loopback *next; + unsigned long id; + grub_off_t skip; +}; + +static struct grub_loopback *loopback_list; +static unsigned long last_id = 0; + +static const struct grub_arg_option options[] = + { + /* TRANSLATORS: The disk is simply removed from the list of available ones, + not wiped, avoid to scare user. */ + {"delete", 'd', 0, N_("Delete the specified loopback drive."), 0, 0}, + {"skip", 's', 0, "skip sectors of the file.", "SECTORS", ARG_TYPE_INT }, + {0, 0, 0, 0, 0, 0} + }; + +/* Delete the loopback device NAME. */ +static grub_err_t +delete_loopback (const char *name) +{ + struct grub_loopback *dev; + struct grub_loopback **prev; + + /* Search for the device. */ + for (dev = loopback_list, prev = &loopback_list; + dev; + prev = &dev->next, dev = dev->next) + if (grub_strcmp (dev->devname, name) == 0) + break; + + if (! dev) + return grub_error (GRUB_ERR_BAD_DEVICE, "device not found"); + + /* Remove the device from the list. */ + *prev = dev->next; + + grub_free (dev->devname); + grub_file_close (dev->file); + grub_free (dev); + + return 0; +} + +/* The command to add and remove loopback devices. */ +static grub_err_t +grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + grub_file_t file; + struct grub_loopback *newdev; + grub_err_t ret; + grub_off_t skip = 0; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + + /* Check if `-d' was used. */ + if (state[0].set) + return delete_loopback (args[0]); + + if (state[1].set) + skip = (grub_off_t)grub_strtoull(state[1].arg, NULL, 10); + + if (argc < 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + file = grub_file_open (args[1], GRUB_FILE_TYPE_LOOPBACK + | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + return grub_errno; + + /* First try to replace the old device. */ + for (newdev = loopback_list; newdev; newdev = newdev->next) + if (grub_strcmp (newdev->devname, args[0]) == 0) + break; + + if (newdev) + { + grub_file_close (newdev->file); + newdev->file = file; + newdev->skip = skip; + + return 0; + } + + /* Unable to replace it, make a new entry. */ + newdev = grub_malloc (sizeof (struct grub_loopback)); + if (! newdev) + goto fail; + + newdev->devname = grub_strdup (args[0]); + if (! newdev->devname) + { + grub_free (newdev); + goto fail; + } + + newdev->file = file; + newdev->skip = skip; + newdev->id = last_id++; + + /* Add the new entry to the list. */ + newdev->next = loopback_list; + loopback_list = newdev; + + return 0; + +fail: + ret = grub_errno; + grub_file_close (file); + return ret; +} + + +static int +grub_loopback_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +{ + struct grub_loopback *d; + if (pull != GRUB_DISK_PULL_NONE) + return 0; + for (d = loopback_list; d; d = d->next) + { + if (hook (d->devname, hook_data)) + return 1; + } + return 0; +} + +static grub_err_t +grub_loopback_open (const char *name, grub_disk_t disk) +{ + struct grub_loopback *dev; + + for (dev = loopback_list; dev; dev = dev->next) + if (grub_strcmp (dev->devname, name) == 0) + break; + + if (! dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + + /* Use the filesize for the disk size, round up to a complete sector. */ + if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN) + disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) + / GRUB_DISK_SECTOR_SIZE); + else + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + /* Avoid reading more than 512M. */ + disk->max_agglomerate = 1 << (29 - GRUB_DISK_SECTOR_BITS + - GRUB_DISK_CACHE_BITS); + + disk->id = dev->id; + + disk->data = dev; + + return 0; +} + +static grub_err_t +grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_file_t file = ((struct grub_loopback *) disk->data)->file; + grub_off_t skip = ((struct grub_loopback *) disk->data)->skip; + grub_off_t pos; + + grub_file_seek (file, (sector + skip) << GRUB_DISK_SECTOR_BITS); + + grub_file_read (file, buf, size << GRUB_DISK_SECTOR_BITS); + if (grub_errno) + return grub_errno; + + /* In case there is more data read than there is available, in case + of files that are not a multiple of GRUB_DISK_SECTOR_SIZE, fill + the rest with zeros. */ + pos = (sector + skip + size) << GRUB_DISK_SECTOR_BITS; + if (pos > file->size) + { + grub_size_t amount = pos - file->size; + grub_memset (buf + (size << GRUB_DISK_SECTOR_BITS) - amount, 0, amount); + } + + return 0; +} + +static grub_err_t +grub_loopback_write (grub_disk_t disk __attribute ((unused)), + grub_disk_addr_t sector __attribute ((unused)), + grub_size_t size __attribute ((unused)), + const char *buf __attribute ((unused))) +{ + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "loopback write is not supported"); +} + +static struct grub_disk_dev grub_loopback_dev = + { + .name = "loopback", + .id = GRUB_DISK_DEVICE_LOOPBACK_ID, + .disk_iterate = grub_loopback_iterate, + .disk_open = grub_loopback_open, + .disk_read = grub_loopback_read, + .disk_write = grub_loopback_write, + .next = 0 + }; + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(loopback) +{ + cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, 0, + N_("[-d] DEVICENAME FILE."), + /* TRANSLATORS: The file itself is not destroyed + or transformed into drive. */ + N_("Make a virtual drive from a file."), options); + grub_disk_dev_register (&grub_loopback_dev); +} + +GRUB_MOD_FINI(loopback) +{ + grub_unregister_extcmd (cmd); + grub_disk_dev_unregister (&grub_loopback_dev); +} diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c index 6f9d7262..97f4ee16 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c @@ -3148,6 +3148,22 @@ static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int ar VENTOY_CMD_RETURN(GRUB_ERR_NONE); } +static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char buf[32]; + ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace); + + (void)ctxt; + + if (argc >= 1) + { + grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt); + grub_env_set(args[0], buf); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args) { (void)ctxt; @@ -4425,6 +4441,194 @@ static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc VENTOY_CMD_RETURN(0); } +static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t i; + grub_uint32_t loadsector = 0; + grub_file_t file; + char value[32]; + grub_uint32_t boot_catlog = 0; + grub_uint8_t buf[512]; + + (void)ctxt; + + if (argc != 2) + { + debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc); + return 1; + } + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + debug("failed to open %s\n", args[0]); + return 1; + } + + boot_catlog = ventoy_get_iso_boot_catlog(file); + if (boot_catlog == 0) + { + debug("No bootcatlog found\n"); + grub_file_close(file); + return 1; + } + + grub_memset(buf, 0, sizeof(buf)); + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, buf, sizeof(buf)); + grub_file_close(file); + + for (i = 0; i < sizeof(buf); i += 32) + { + if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF) + { + if (buf[i + 32] == 0x88) + { + loadsector = *(grub_uint32_t *)(buf + i + 32 + 8); + grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512 + break; + } + } + } + + if (loadsector == 0) + { + debug("No EFI eltorito info found\n"); + return 1; + } + + debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value); + grub_env_set(args[1], value); + VENTOY_CMD_RETURN(0); +} + +static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + int curpos; + int printlen; + grub_size_t len; + replace_fs_dir *pfsdir = (replace_fs_dir *)data; + + if (pfsdir->initrd[0]) + { + return 1; + } + + curpos = pfsdir->curpos; + len = grub_strlen(filename); + + if (info->dir) + { + if ((len == 1 && filename[0] == '.') || + (len == 2 && filename[0] == '.' && filename[1] == '.')) + { + return 0; + } + + //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename); + pfsdir->dircnt++; + + printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename); + pfsdir->curpos = curpos + printlen; + pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir); + pfsdir->curpos = curpos; + pfsdir->fullpath[curpos] = 0; + } + else + { + //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename); + pfsdir->filecnt++; + + /* We consider the xxx.img file bigger than 32MB is the initramfs file */ + if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0) + { + if (info->size > 32 * VTOY_SIZE_1MB) + { + grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename); + return 1; + } + } + } + + return 0; +} + +static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + char *pos = NULL; + char *device_name = NULL; + grub_device_t dev = NULL; + grub_fs_t fs = NULL; + replace_fs_dir *pfsdir = NULL; + + (void)ctxt; + + if (argc != 2) + { + debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc); + return 1; + } + + pfsdir = grub_zalloc(sizeof(replace_fs_dir)); + if (!pfsdir) + { + return 1; + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + goto fail; + } + + dev = grub_device_open(device_name); + if (!dev) + { + goto fail; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + goto fail; + } + + pfsdir->dev = dev; + pfsdir->fs = fs; + pfsdir->curpos = 1; + pfsdir->fullpath[0] = '/'; + fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir); + + if (pfsdir->initrd[0]) + { + debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt); + + for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++) + { + if (pfsdir->initrd[i] == '/') + { + pfsdir->initrd[i] = '\\'; + } + } + + pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd; + grub_env_set(args[1], pos); + } + else + { + debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt); + } + +fail: + + grub_check_free(pfsdir); + grub_check_free(device_name); + check_free(dev, grub_device_close); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + int ventoy_env_init(void) { char buf[64]; @@ -4560,6 +4764,7 @@ static cmd_para ventoy_cmds[] = { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL }, { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL }, + { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL }, { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL }, { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL }, @@ -4596,6 +4801,8 @@ static cmd_para ventoy_cmds[] = { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL }, { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL }, + { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL }, + { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL }, }; int ventoy_register_all_cmd(void) diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h index 4c349707..b5240114 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h @@ -533,6 +533,17 @@ typedef struct plugin_entry ventoy_plugin_check_pf checkfunc; }plugin_entry; +typedef struct replace_fs_dir +{ + grub_device_t dev; + grub_fs_t fs; + char fullpath[512]; + char initrd[512]; + int curpos; + int dircnt; + int filecnt; +}replace_fs_dir; + int ventoy_strcmp(const char *pattern, const char *str); int ventoy_strncmp (const char *pattern, const char *str, grub_size_t n); void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param); diff --git a/INSTALL/grub/grub.cfg b/INSTALL/grub/grub.cfg index 1d72aa22..d1565ef7 100644 --- a/INSTALL/grub/grub.cfg +++ b/INSTALL/grub/grub.cfg @@ -548,6 +548,23 @@ function uefi_windows_menu_func { fi } +function uefi_find_replace_initrd { + if vt_get_efi_vdisk_offset "${1}${2}" vt_efivdisk_offset; then + loopback -s $vt_efivdisk_offset vtefivdisk "${1}${2}" + + unset vt_rp_initrd + vt_search_replace_initrd (vtefivdisk) vt_rp_initrd + + if [ -n "$vt_rp_initrd" ]; then + vt_add_replace_file $3 "$vt_rp_initrd" + echo vt_add_replace_file $3 "$vt_rp_initrd" + fi + + loopback -d vtefivdisk + ventoy_debug_pause + fi +} + function uefi_linux_menu_func { if [ "$ventoy_compatible" = "NO" ]; then @@ -629,6 +646,11 @@ function uefi_linux_menu_func { elif [ -f (loop)/loader/entries/pisi-efi-x86_64.conf ]; then vt_add_replace_file $vtindex "EFI\\pisi\\initrd.img" fi + + vt_get_replace_file_cnt vt_replace_cnt + if [ $vt_replace_cnt -eq 0 ]; then + uefi_find_replace_initrd "$1" "$2" $vtindex + fi elif [ -d (loop)/EFI/boot/entries ]; then if [ -f (loop)/parabola/boot/x86_64/parabolaiso.img ]; then vt_add_replace_file 0 "EFI\\parabolaiso\\parabolaiso.img"