#include <grub/datetime.h>
#include <grub/i18n.h>
#include <grub/net.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#endif
#include <grub/time.h>
#include <grub/ventoy.h>
#include "ventoy_def.h"
static grub_file_t g_old_file;
char g_img_swap_tmp_buf[1024];
-
+img_info g_img_swap_tmp;
img_info *g_ventoy_img_list = NULL;
int g_ventoy_img_count = 0;
+grub_device_t g_enum_dev = NULL;
+grub_fs_t g_enum_fs = NULL;
img_iterator_node g_img_iterator_head;
+img_iterator_node *g_img_iterator_tail = NULL;
grub_uint8_t g_ventoy_break_level = 0;
grub_uint8_t g_ventoy_debug_level = 0;
cpio_newc_header *g_ventoy_initrd_head = NULL;
grub_uint8_t *g_ventoy_runtime_buf = NULL;
-ventoy_grub_param g_grub_param;
+ventoy_grub_param *g_grub_param = NULL;
ventoy_guid g_ventoy_guid = VENTOY_GUID;
ventoy_img_chunk_list g_img_chunk_list;
+static char *g_tree_script_buf = NULL;
+static int g_tree_script_pos = 0;
+
+static char *g_list_script_buf = NULL;
+static int g_list_script_pos = 0;
+
+
void ventoy_debug(const char *fmt, ...)
{
va_list args;
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
+static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int rc = 1;
+ char buf[32];
+ grub_file_t file;
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ if (argc != 2)
+ {
+ return rc;
+ }
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
+ if (file == NULL)
+ {
+ debug("failed to open file <%s> for udf check\n", args[0]);
+ return 1;
+ }
+
+ grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size);
+
+ grub_env_set(args[1], buf);
+
+ grub_file_close(file);
+ rc = 0;
+
+ return rc;
+}
+
+static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int rc = 1;
+ char name[32];
+ char value[32];
+ char *buf = NULL;
+ grub_file_t file;
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ if (argc != 2)
+ {
+ return rc;
+ }
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
+ if (file == NULL)
+ {
+ debug("failed to open file <%s> for udf check\n", args[0]);
+ return 1;
+ }
+
+#ifdef GRUB_MACHINE_EFI
+ buf = (char *)grub_efi_allocate_iso_buf(file->size);
+#else
+ buf = (char *)grub_malloc(file->size);
+#endif
+
+ grub_file_read(file, buf, file->size);
+
+ grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
+ grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
+ grub_env_set(name, value);
+
+ grub_snprintf(name, sizeof(name), "%s_size", args[1]);
+ grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
+ grub_env_set(name, value);
+
+ grub_file_close(file);
+ rc = 0;
+
+ return rc;
+}
+
static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args)
{
int i;
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
-static int ventoy_cmp_img(img_info *img1, img_info *img2)
+int ventoy_cmp_img(img_info *img1, img_info *img2)
{
char *s1, *s2;
int c1 = 0;
return (c1 - c2);
}
-static void ventoy_swap_img(img_info *img1, img_info *img2)
+void ventoy_swap_img(img_info *img1, img_info *img2)
{
- grub_memcpy(g_img_swap_tmp_buf, img1->name, sizeof(img1->name));
- grub_memcpy(img1->name, img2->name, sizeof(img1->name));
- grub_memcpy(img2->name, g_img_swap_tmp_buf, sizeof(img1->name));
+ grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info));
- grub_memcpy(g_img_swap_tmp_buf, img1->path, sizeof(img1->path));
- grub_memcpy(img1->path, img2->path, sizeof(img1->path));
- grub_memcpy(img2->path, g_img_swap_tmp_buf, sizeof(img1->path));
+ grub_memcpy(img1, img2, sizeof(img_info));
+ img1->next = g_img_swap_tmp.next;
+ img1->prev = g_img_swap_tmp.prev;
+
+ g_img_swap_tmp.next = img2->next;
+ g_img_swap_tmp.prev = img2->prev;
+ grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info));
}
static int ventoy_img_name_valid(const char *filename, grub_size_t namelen)
return 1;
}
+static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data)
+{
+ if (0 == info->dir)
+ {
+ if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13))
+ {
+ *((int *)data) = 1;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
static int ventoy_colect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data)
{
+ int ignore = 0;
grub_size_t len;
img_info *img;
img_info *tail;
+ img_iterator_node *tmp;
img_iterator_node *new_node;
img_iterator_node *node = (img_iterator_node *)data;
return 0;
}
- new_node = grub_malloc(sizeof(img_iterator_node));
+ if (!ventoy_img_name_valid(filename, len))
+ {
+ return 0;
+ }
+
+ if (filename[0] == '$' && 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12))
+ {
+ return 0;
+ }
+
+ new_node = grub_zalloc(sizeof(img_iterator_node));
if (new_node)
{
+ new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
+
+ g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore);
+ if (ignore)
+ {
+ debug("Directory %s ignored...\n", new_node->dir);
+ grub_free(new_node);
+ return 0;
+ }
+
new_node->tail = node->tail;
- grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename);
- new_node->next = g_img_iterator_head.next;
- g_img_iterator_head.next = new_node;
+ new_node->parent = node;
+ if (!node->firstchild)
+ {
+ node->firstchild = new_node;
+ }
+
+ if (g_img_iterator_tail)
+ {
+ g_img_iterator_tail->next = new_node;
+ g_img_iterator_tail = new_node;
+ }
+ else
+ {
+ g_img_iterator_head.next = new_node;
+ g_img_iterator_tail = new_node;
+ }
}
}
else
{
g_ventoy_img_list = img;
}
+
+ img->size = info->size;
+ img->id = g_ventoy_img_count;
+ img->parent = node;
+ if (node && NULL == node->firstiso)
+ {
+ node->firstiso = img;
+ }
+
+ node->isocnt++;
+ tmp = node->parent;
+ while (tmp)
+ {
+ tmp->isocnt++;
+ tmp = tmp->parent;
+ }
*((img_info **)(node->tail)) = img;
g_ventoy_img_count++;
return len;
}
+static img_info * ventoy_get_min_iso(img_iterator_node *node)
+{
+ img_info *minimg = NULL;
+ img_info *img = (img_info *)(node->firstiso);
+
+ while (img && (img_iterator_node *)(img->parent) == node)
+ {
+ if (img->select == 0 && (NULL == minimg || grub_strcmp(img->name, minimg->name) < 0))
+ {
+ minimg = img;
+ }
+ img = img->next;
+ }
+
+ if (minimg)
+ {
+ minimg->select = 1;
+ }
+
+ return minimg;
+}
+
+static img_iterator_node * ventoy_get_min_child(img_iterator_node *node)
+{
+ img_iterator_node *Minchild = NULL;
+ img_iterator_node *child = node->firstchild;
+
+ while (child && child->parent == node)
+ {
+ if (child->select == 0 && (NULL == Minchild || grub_strcmp(child->dir, Minchild->dir) < 0))
+ {
+ Minchild = child;
+ }
+ child = child->next;
+ }
+
+ if (Minchild)
+ {
+ Minchild->select = 1;
+ }
+
+ return Minchild;
+}
+
+static int ventoy_dynamic_tree_menu(img_iterator_node *node)
+{
+ int offset = 1;
+ img_info *img;
+ img_iterator_node *child = NULL;
+
+ if (node->isocnt == 0 || node->done == 1)
+ {
+ return 0;
+ }
+
+ if (node->parent && node->parent->dirlen < node->dirlen)
+ {
+ offset = node->parent->dirlen;
+ }
+
+ if (node != &g_img_iterator_head)
+ {
+ node->dir[node->dirlen - 1] = 0;
+ g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
+ "submenu \"%-10s [%s]\" {\n", "DIR", node->dir + offset);
+ }
+
+ while ((child = ventoy_get_min_child(node)) != NULL)
+ {
+ ventoy_dynamic_tree_menu(child);
+ }
+
+ while ((img = ventoy_get_min_iso(node)) != NULL)
+ {
+ g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos,
+ "menuentry \"%-10s %s\" --id=\"VID_%d\" {\n"
+ " common_menuentry \n"
+ "}\n",
+ grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), img->name, img->id);
+ }
+
+ if (node != &g_img_iterator_head)
+ {
+ g_tree_script_pos += grub_snprintf(g_tree_script_buf + g_tree_script_pos, VTOY_MAX_SCRIPT_BUF - g_tree_script_pos, "}\n");
+ }
+
+ node->done = 1;
+ return 0;
+}
+
static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_fs_t fs;
char *device_name = NULL;
char buf[32];
img_iterator_node *node = NULL;
+ img_iterator_node *tmp = NULL;
(void)ctxt;
goto fail;
}
- dev = grub_device_open(device_name);
+ g_enum_dev = dev = grub_device_open(device_name);
if (!dev)
{
goto fail;
}
- fs = grub_fs_probe(dev);
+ g_enum_fs = fs = grub_fs_probe(dev);
if (!fs)
{
goto fail;
grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head));
+ g_img_iterator_head.dirlen = 1;
g_img_iterator_head.tail = &tail;
- grub_strcpy(g_img_iterator_head.dir, "/");
+ grub_strcpy(g_img_iterator_head.dir, "/");
- fs->fs_dir(dev, "/", ventoy_colect_img_files, &g_img_iterator_head);
+ for (node = &g_img_iterator_head; node; node = node->next)
+ {
+ fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
+ }
- while (g_img_iterator_head.next)
+ for (node = &g_img_iterator_head; node; node = node->next)
{
- node = g_img_iterator_head.next;
- g_img_iterator_head.next = node->next;
+ ventoy_dynamic_tree_menu(node);
+ }
- fs->fs_dir(dev, node->dir, ventoy_colect_img_files, node);
+ /* free node */
+ node = g_img_iterator_head.next;
+ while (node)
+ {
+ tmp = node->next;
grub_free(node);
+ node = tmp;
}
-
+
/* sort image list by image name */
for (cur = g_ventoy_img_list; cur; cur = cur->next)
{
}
}
+ for (cur = g_ventoy_img_list; cur; cur = cur->next)
+ {
+ g_list_script_pos += grub_snprintf(g_list_script_buf + g_list_script_pos, VTOY_MAX_SCRIPT_BUF - g_list_script_pos,
+ "menuentry \"%s\" --id=\"VID_%d\" {\n"
+ " common_menuentry \n"
+ "}\n",
+ cur->name, cur->id);
+ }
+ g_list_script_buf[g_list_script_pos] = 0;
+
grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count);
grub_env_set(args[1], buf);
static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
{
- const char *name = NULL;
+ int img_id = 0;
+ char *pos = NULL;
+ const char *id = NULL;
img_info *cur = g_ventoy_img_list;
(void)ctxt;
return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
}
- name = grub_env_get("chosen");
+ id = grub_env_get("chosen");
+
+ pos = grub_strstr(id, "VID_");
+ if (pos)
+ {
+ img_id = (int)grub_strtoul(pos + 4, NULL, 10);
+ }
+ else
+ {
+ img_id = (int)grub_strtoul(id, NULL, 10);
+ }
while (cur)
{
- if (0 == grub_strcmp(name, cur->name))
+ if (img_id == cur->id)
{
- grub_env_set(args[0], cur->path);
break;
}
cur = cur->next;
return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image");
}
+ grub_env_set(args[0], cur->path);
+
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
grub_file_close(file);
+ grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace));
+
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
+static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int i;
+ ventoy_grub_param_file_replace *replace = NULL;
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ if (argc >= 2)
+ {
+ replace = &(g_grub_param->file_replace);
+ replace->magic = GRUB_FILE_REPLACE_MAGIC;
+
+ replace->old_name_cnt = 0;
+ for (i = 0; i < 4 && i + 1 < argc; i++)
+ {
+ replace->old_name_cnt++;
+ grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]);
+ }
+
+ replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10);
+ }
+
+ 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;
+ (void)argc;
+ (void)args;
+
+ if (argc == 0)
+ {
+ grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF);
+ grub_printf("%s", g_list_script_buf);
+ }
+ else
+ {
+ grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF);
+ grub_printf("%s", g_tree_script_buf);
+ }
+
+ return 0;
+}
+
+static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ ventoy_plugin_dump_auto_install();
+
+ return 0;
+}
+
+static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ if (argc != 1)
+ {
+ return 1;
+ }
+
+ if (args[0][0] == '0')
+ {
+ return g_ventoy_memdisk_mode ? 0 : 1;
+ }
+ else if (args[0][0] == '1')
+ {
+ return g_ventoy_iso_raw ? 0 : 1;
+ }
+ else if (args[0][0] == '2')
+ {
+ return g_ventoy_iso_uefi_drv ? 0 : 1;
+ }
+
+ return 1;
+}
+
+static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ static int configfile_mode = 0;
+ char memfile[128] = {0};
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ /*
+ * args[0]: 0:normal 1:configfile
+ * args[1]: 0:list_buf 1:tree_buf
+ */
+
+ if (argc != 2)
+ {
+ debug("Invlaid argc %d\n", argc);
+ return 0;
+ }
+
+ if (args[0][0] == '0')
+ {
+ if (args[1][0] == '0')
+ {
+ grub_script_execute_sourcecode(g_list_script_buf);
+ }
+ else
+ {
+ grub_script_execute_sourcecode(g_tree_script_buf);
+ }
+ }
+ else
+ {
+ if (configfile_mode)
+ {
+ debug("Now already in F3 mode %d\n", configfile_mode);
+ return 0;
+ }
+
+ if (args[1][0] == '0')
+ {
+ grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
+ (ulonglong)(ulong)g_list_script_buf, g_list_script_pos);
+ }
+ else
+ {
+ g_ventoy_last_entry = -1;
+ grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d",
+ (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos);
+ }
+
+ configfile_mode = 1;
+ grub_script_execute_sourcecode(memfile);
+ configfile_mode = 0;
+ }
+
+ return 0;
+}
+
+static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int id = 0;
+ int find = 0;
+ grub_disk_t disk;
+ const char *isopath = NULL;
+ char hdname[32];
+ ventoy_mbr_head mbr;
+
+ (void)ctxt;
+ (void)argc;
+
+ if (argc != 1)
+ {
+ return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name);
+ }
+
+ isopath = grub_env_get("iso_path");
+ if (!isopath)
+ {
+ debug("isopath is null %p\n", isopath);
+ return 0;
+ }
+
+ debug("isopath is %s\n", isopath);
+
+ for (id = 0; id < 30 && (find == 0); id++)
+ {
+ grub_snprintf(hdname, sizeof(hdname), "hd%d,", id);
+ if (grub_strstr(isopath, hdname))
+ {
+ debug("skip %s ...\n", hdname);
+ continue;
+ }
+
+ grub_snprintf(hdname, sizeof(hdname), "hd%d", id);
+
+ disk = grub_disk_open(hdname);
+ if (!disk)
+ {
+ debug("%s not exist\n", hdname);
+ break;
+ }
+
+ grub_memset(&mbr, 0, sizeof(mbr));
+ if (0 == grub_disk_read(disk, 0, 0, 512, &mbr))
+ {
+ if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA)
+ {
+ if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 ||
+ mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80)
+ {
+
+ grub_env_set(args[0], hdname);
+ find = 1;
+ }
+ }
+ debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable");
+ }
+ else
+ {
+ debug("read %s failed\n", hdname);
+ }
+
+ grub_disk_close(disk);
+ }
+
+ return 0;
+}
+
grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...)
{
va_list ap;
char buf[64];
grub_env_set("vtdebug_flag", "");
+ grub_env_export("vtdebug_flag");
+
+ g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
+ g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF);
ventoy_filt_register(0, ventoy_wrapper_open);
-
- g_grub_param.grub_env_get = grub_env_get;
- grub_snprintf(buf, sizeof(buf), "%p", &g_grub_param);
- grub_env_set("env_param", buf);
+
+ g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param));
+ if (g_grub_param)
+ {
+ g_grub_param->grub_env_get = grub_env_get;
+ grub_snprintf(buf, sizeof(buf), "%p", g_grub_param);
+ grub_env_set("env_param", buf);
+ }
return 0;
}
{ "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
{ "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
{ "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
+ { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
+ { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
+ { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
+ { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL },
+ { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL },
{ "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
+ { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
+ { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
{ "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
{ "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
{ "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL },
{ "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL },
{ "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL },
+ { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL },
{ "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL },
{ "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL },
{ "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL },
{ "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim, 0, NULL, "", "", NULL },
{ "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL },
+
+ { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL },
+
{ "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL },
};