1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/misc.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
36 #include <grub/misc.h>
37 #include <grub/kernel.h>
38 #ifdef GRUB_MACHINE_EFI
39 #include <grub/efi/api.h>
40 #include <grub/efi/efi.h>
42 #include <grub/time.h>
43 #include <grub/video.h>
44 #include <grub/acpi.h>
45 #include <grub/charset.h>
46 #include <grub/crypto.h>
47 #include <grub/lib/crc.h>
48 #include <grub/ventoy.h>
49 #include "ventoy_def.h"
52 GRUB_MOD_LICENSE ("GPLv3+");
54 int g_ventoy_debug
= 0;
55 static int g_efi_os
= 0xFF;
56 initrd_info
*g_initrd_img_list
= NULL
;
57 initrd_info
*g_initrd_img_tail
= NULL
;
58 int g_initrd_img_count
= 0;
59 int g_valid_initrd_count
= 0;
60 int g_default_menu_mode
= 0;
61 int g_filt_dot_underscore_file
= 0;
62 int g_sort_case_sensitive
= 0;
63 int g_tree_view_menu_style
= 0;
64 static grub_file_t g_old_file
;
65 static int g_ventoy_last_entry_back
;
66 static grub_uint32_t g_ventoy_plat_data
;
69 char g_img_swap_tmp_buf
[1024];
70 img_info g_img_swap_tmp
;
71 img_info
*g_ventoy_img_list
= NULL
;
73 int g_ventoy_img_count
= 0;
75 grub_device_t g_enum_dev
= NULL
;
76 grub_fs_t g_enum_fs
= NULL
;
77 img_iterator_node g_img_iterator_head
;
78 img_iterator_node
*g_img_iterator_tail
= NULL
;
80 grub_uint8_t g_ventoy_break_level
= 0;
81 grub_uint8_t g_ventoy_debug_level
= 0;
82 grub_uint8_t g_ventoy_chain_type
= 0;
84 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
85 grub_uint32_t g_ventoy_cpio_size
= 0;
86 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
87 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
89 int g_plugin_image_list
= 0;
91 ventoy_grub_param
*g_grub_param
= NULL
;
93 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
95 ventoy_img_chunk_list g_img_chunk_list
;
97 int g_wimboot_enable
= 0;
98 ventoy_img_chunk_list g_wimiso_chunk_list
;
99 char *g_wimiso_path
= NULL
;
101 int g_vhdboot_enable
= 0;
103 grub_uint64_t g_conf_replace_offset
= 0;
104 grub_uint64_t g_svd_replace_offset
= 0;
105 conf_replace
*g_conf_replace_node
= NULL
;
106 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
107 int g_conf_replace_new_len
= 0;
108 int g_conf_replace_new_len_align
= 0;
110 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
111 grub_uint64_t g_ventoy_disk_size
= 0;
113 static char *g_tree_script_buf
= NULL
;
114 static int g_tree_script_pos
= 0;
116 static char *g_list_script_buf
= NULL
;
117 static int g_list_script_pos
= 0;
119 static char *g_part_list_buf
= NULL
;
120 static int g_part_list_pos
= 0;
122 static int g_video_mode_max
= 0;
123 static int g_video_mode_num
= 0;
124 static ventoy_video_mode
*g_video_mode_list
= NULL
;
126 static const char *g_menu_class
[] =
128 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
131 static const char *g_menu_prefix
[] =
133 "iso", "wim", "efi", "img", "vhd", "vtoy"
136 void ventoy_debug(const char *fmt
, ...)
140 va_start (args
, fmt
);
141 grub_vprintf (fmt
, args
);
145 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
155 for (i
= 0; i
< 16; i
++)
157 grub_printf("%02x ", guid
[i
]);
162 int ventoy_is_efi_os(void)
166 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
172 static int ventoy_get_fs_type(const char *fs
)
176 return ventoy_fs_max
;
178 else if (grub_strncmp(fs
, "exfat", 5) == 0)
180 return ventoy_fs_exfat
;
182 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
184 return ventoy_fs_ntfs
;
186 else if (grub_strncmp(fs
, "ext", 3) == 0)
188 return ventoy_fs_ext
;
190 else if (grub_strncmp(fs
, "xfs", 3) == 0)
192 return ventoy_fs_xfs
;
194 else if (grub_strncmp(fs
, "udf", 3) == 0)
196 return ventoy_fs_udf
;
198 else if (grub_strncmp(fs
, "fat", 3) == 0)
200 return ventoy_fs_fat
;
203 return ventoy_fs_max
;
206 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
225 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
227 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
231 static grub_err_t
ventoy_fs_close(grub_file_t file
)
233 grub_file_close(g_old_file
);
234 grub_free(file
->data
);
242 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
248 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
253 for (i
= 0; i
< g_video_mode_num
; i
++)
255 if (g_video_mode_list
[i
].width
== info
->width
&&
256 g_video_mode_list
[i
].height
== info
->height
&&
257 g_video_mode_list
[i
].bpp
== info
->bpp
)
263 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
264 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
265 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
268 if (g_video_mode_num
== g_video_mode_max
)
270 g_video_mode_max
*= 2;
271 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
277 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
279 if (v1
->bpp
== v2
->bpp
)
281 if (v1
->width
== v2
->width
)
283 if (v1
->height
== v2
->height
)
289 return (v1
->height
< v2
->height
) ? -1 : 1;
294 return (v1
->width
< v2
->width
) ? -1 : 1;
299 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
303 static int ventoy_enum_video_mode(void)
306 grub_video_adapter_t adapter
;
307 grub_video_driver_id_t id
;
308 ventoy_video_mode mode
;
310 g_video_mode_num
= 0;
311 g_video_mode_max
= 1024;
312 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
313 if (!g_video_mode_list
)
318 #ifdef GRUB_MACHINE_PCBIOS
319 grub_dl_load ("vbe");
322 id
= grub_video_get_driver_id ();
324 FOR_VIDEO_ADAPTERS (adapter
)
326 if (!adapter
->iterate
||
327 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
328 adapter
->init() != GRUB_ERR_NONE
)))
333 adapter
->iterate(ventoy_video_hook
, NULL
);
335 if (adapter
->id
!= id
)
341 /* sort video mode */
342 for (i
= 0; i
< g_video_mode_num
; i
++)
343 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
345 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
347 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
348 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
349 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
353 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
356 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
360 static struct grub_fs vtoy_fs
=
365 .fs_read
= ventoy_fs_read
,
366 .fs_close
= ventoy_fs_close
,
376 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
382 file
->data
= grub_malloc(rawFile
->size
+ 4096);
388 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
389 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
391 g_old_file
= rawFile
;
393 file
->size
= rawFile
->size
+ len
;
394 file
->device
= rawFile
->device
;
396 file
->not_easily_seekable
= 1;
401 static int ventoy_check_decimal_var(const char *name
, long *value
)
403 const char *value_str
= NULL
;
405 value_str
= grub_env_get(name
);
406 if (NULL
== value_str
)
408 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
411 if (!ventoy_is_decimal(value_str
))
413 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
416 *value
= grub_strtol(value_str
, NULL
, 10);
418 return GRUB_ERR_NONE
;
421 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
425 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
428 if (0 == grub_strcmp(args
[0], "on"))
431 grub_env_set("vtdebug_flag", "debug");
436 grub_env_set("vtdebug_flag", "");
439 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
442 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
446 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
448 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
449 grub_printf(" level:\r\n");
450 grub_printf(" 01/11: busybox / (+cat log)\r\n");
451 grub_printf(" 02/12: initrd / (+cat log)\r\n");
452 grub_printf(" 03/13: hook / (+cat log)\r\n");
454 grub_printf(" debug:\r\n");
455 grub_printf(" 0: debug is off\r\n");
456 grub_printf(" 1: debug is on\r\n");
458 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
461 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
463 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
465 g_ventoy_debug_level
= 1;
468 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
471 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
480 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
483 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
515 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
520 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
522 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
525 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
530 value_long
+= grub_strtol(args
[1], NULL
, 10);
532 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
533 grub_env_set(args
[0], buf
);
535 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
538 static grub_err_t
ventoy_cmd_mod(grub_extcmd_context_t ctxt
, int argc
, char **args
)
546 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name
);
549 value1
= grub_strtol(args
[0], NULL
, 10);
550 value2
= grub_strtol(args
[1], NULL
, 10);
552 grub_snprintf(buf
, sizeof(buf
), "%ld", (value1
% value2
));
553 grub_env_set(args
[2], buf
);
555 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
558 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
573 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
576 debug("failed to open file <%s> for udf check\n", args
[0]);
580 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
582 grub_env_set(args
[1], buf
);
584 grub_file_close(file
);
590 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
598 g_wimboot_enable
= 0;
599 grub_check_free(g_wimiso_path
);
600 grub_check_free(g_wimiso_chunk_list
.chunk
);
602 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
608 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
609 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
610 if (NULL
== g_wimiso_chunk_list
.chunk
)
612 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
615 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
616 g_wimiso_chunk_list
.cur_chunk
= 0;
618 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
620 g_wimboot_enable
= 1;
621 g_wimiso_path
= grub_strdup(args
[0]);
623 grub_file_close(file
);
628 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
634 grub_uint32_t offset
;
636 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
639 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
643 len
= (int)file
->size
;
645 data
= (char *)grub_malloc(file
->size
);
651 grub_file_read(file
, data
, file
->size
);
652 grub_file_close(file
);
654 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
655 grub_script_execute_sourcecode(exec
);
657 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
658 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
659 grub_file_close(file
);
661 grub_script_execute_sourcecode("loopback -d efiboot");
665 *direntoff
= offset
+ 2;
670 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
680 ventoy_iso9660_override
*dirent
;
689 totlen
= sizeof(ventoy_chain_head
);
691 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
693 debug("failed to load efiboot template %d\n", len
);
699 debug("efiboot template len:%d offset:%d\n", len
, offset
);
701 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
704 debug("failed to open file <%s>\n", args
[0]);
708 totlen
+= ventoy_align_2k(file
->size
);
710 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
711 dirent
->first_sector
= len
/ 2048;
712 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
713 dirent
->size
= (grub_uint32_t
)file
->size
;
714 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
716 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
718 #ifdef GRUB_MACHINE_EFI
719 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
721 data
= (char *)grub_malloc(totlen
);
724 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
726 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
727 grub_check_free(buf
);
729 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
730 grub_file_close(file
);
732 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
733 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
734 grub_env_set(name
, value
);
736 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
737 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
738 grub_env_set(name
, value
);
743 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
760 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
763 debug("failed to open file <%s>\n", args
[0]);
767 #ifdef GRUB_MACHINE_EFI
768 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
770 buf
= (char *)grub_malloc(file
->size
);
773 grub_file_read(file
, buf
, file
->size
);
775 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
776 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
777 grub_env_set(name
, value
);
779 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
780 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
781 grub_env_set(name
, value
);
783 grub_file_close(file
);
789 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
807 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
810 debug("failed to open file <%s> for udf check\n", args
[0]);
814 headlen
= sizeof(ventoy_chain_head
);
816 #ifdef GRUB_MACHINE_EFI
817 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
819 buf
= (char *)grub_malloc(headlen
+ file
->size
);
822 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
824 grub_file_read(file
, buf
+ headlen
, file
->size
);
826 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
827 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
828 grub_env_set(name
, value
);
830 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
831 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
832 grub_env_set(name
, value
);
834 grub_file_close(file
);
840 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
849 if (args
[0][0] == '1')
851 grub_iso9660_set_nojoliet(1);
855 grub_iso9660_set_nojoliet(0);
861 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
866 grub_uint8_t buf
[32];
877 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
880 debug("failed to open file <%s> for udf check\n", args
[0]);
884 for (i
= 16; i
< 32; i
++)
886 grub_file_seek(file
, i
* 2048);
887 grub_file_read(file
, buf
, sizeof(buf
));
895 grub_file_seek(file
, i
* 2048);
896 grub_file_read(file
, buf
, sizeof(buf
));
898 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
901 grub_file_seek(file
, i
* 2048);
902 grub_file_read(file
, buf
, sizeof(buf
));
904 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
905 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
911 grub_file_close(file
);
913 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
918 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
920 long value_long1
= 0;
921 long value_long2
= 0;
923 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
925 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
928 value_long1
= grub_strtol(args
[0], NULL
, 10);
929 value_long2
= grub_strtol(args
[2], NULL
, 10);
931 if (0 == grub_strcmp(args
[1], "eq"))
933 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
935 else if (0 == grub_strcmp(args
[1], "ne"))
937 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
939 else if (0 == grub_strcmp(args
[1], "gt"))
941 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
943 else if (0 == grub_strcmp(args
[1], "lt"))
945 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
947 else if (0 == grub_strcmp(args
[1], "ge"))
949 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
951 else if (0 == grub_strcmp(args
[1], "le"))
953 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
957 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
963 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
970 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
973 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
974 pos
= grub_strstr(buf
, ",");
980 grub_env_set(args
[1], buf
);
982 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
985 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
991 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
997 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
1000 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
1002 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
1003 if (0 == grub_script_execute_sourcecode(buf
))
1005 debug("file %s exist, ventoy_compatible YES\n", buf
);
1006 grub_env_set("ventoy_compatible", "YES");
1007 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1011 debug("file %s NOT exist\n", buf
);
1015 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
1016 pos
= grub_strstr(buf
, ")");
1022 disk
= grub_disk_open(buf
);
1025 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1026 grub_disk_close(disk
);
1028 g_img_swap_tmp_buf
[703] = 0;
1029 for (i
= 318; i
< 703; i
++)
1031 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1032 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1034 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1035 grub_env_set("ventoy_compatible", "YES");
1036 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1042 debug("failed to open disk <%s>\n", buf
);
1045 grub_env_set("ventoy_compatible", "NO");
1046 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1049 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1055 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1057 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1060 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1065 if (0 == g_sort_case_sensitive
)
1067 if (grub_islower(c1
))
1069 c1
= c1
- 'a' + 'A';
1072 if (grub_islower(c2
))
1074 c2
= c2
- 'a' + 'A';
1087 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1093 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1095 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1098 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1103 if (0 == g_sort_case_sensitive
)
1105 if (grub_islower(c1
))
1107 c1
= c1
- 'a' + 'A';
1110 if (grub_islower(c2
))
1112 c2
= c2
- 'a' + 'A';
1125 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1127 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1129 grub_memcpy(img1
, img2
, sizeof(img_info
));
1130 img1
->next
= g_img_swap_tmp
.next
;
1131 img1
->prev
= g_img_swap_tmp
.prev
;
1133 g_img_swap_tmp
.next
= img2
->next
;
1134 g_img_swap_tmp
.prev
= img2
->prev
;
1135 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1138 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1142 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1150 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1154 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1164 static int ventoy_collect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1173 img_iterator_node
*tmp
;
1174 img_iterator_node
*new_node
;
1175 img_iterator_node
*node
= (img_iterator_node
*)data
;
1177 len
= grub_strlen(filename
);
1181 if ((len
== 1 && filename
[0] == '.') ||
1182 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1187 if (!ventoy_img_name_valid(filename
, len
))
1192 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1197 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1199 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1200 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1203 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1208 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1211 new_node
->plugin_list_index
= index
;
1212 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1214 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1217 debug("Directory %s ignored...\n", new_node
->dir
);
1218 grub_free(new_node
);
1222 new_node
->tail
= node
->tail
;
1224 new_node
->parent
= node
;
1225 if (!node
->firstchild
)
1227 node
->firstchild
= new_node
;
1230 if (g_img_iterator_tail
)
1232 g_img_iterator_tail
->next
= new_node
;
1233 g_img_iterator_tail
= new_node
;
1237 g_img_iterator_head
.next
= new_node
;
1238 g_img_iterator_tail
= new_node
;
1244 debug("Find a file %s\n", filename
);
1250 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1252 type
= img_type_iso
;
1254 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1256 type
= img_type_wim
;
1258 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1259 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1261 type
= img_type_vhd
;
1263 #ifdef GRUB_MACHINE_EFI
1264 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1266 type
= img_type_efi
;
1269 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1271 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1273 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1274 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1279 type
= img_type_img
;
1281 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1283 type
= img_type_vtoy
;
1285 else if (len
>= 9 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vcfg"))
1287 if (filename
[len
- 9] == '.' || (len
>= 10 && filename
[len
- 10] == '.'))
1289 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1290 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf
);
1299 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1304 if (g_plugin_image_list
)
1306 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1307 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1308 if (VENTOY_IMG_WHITE_LIST
== g_plugin_image_list
&& index
== 0)
1310 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1313 else if (VENTOY_IMG_BLACK_LIST
== g_plugin_image_list
&& index
> 0)
1315 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf
);
1320 img
= grub_zalloc(sizeof(img_info
));
1324 img
->plugin_list_index
= index
;
1325 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1327 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1329 img
->size
= info
->size
;
1332 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1335 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1337 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1342 if (g_ventoy_img_list
)
1344 tail
= *(node
->tail
);
1350 g_ventoy_img_list
= img
;
1353 img
->id
= g_ventoy_img_count
;
1355 if (node
&& NULL
== node
->firstiso
)
1357 node
->firstiso
= img
;
1368 *((img_info
**)(node
->tail
)) = img
;
1369 g_ventoy_img_count
++;
1371 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1372 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1375 img
->class = g_menu_class
[type
];
1377 img
->menu_prefix
= g_menu_prefix
[type
];
1379 if (img_type_iso
== type
)
1381 if (ventoy_plugin_check_memdisk(img
->path
))
1383 img
->menu_prefix
= "miso";
1387 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1394 static int ventoy_arch_mode_init(void)
1396 #ifdef GRUB_MACHINE_EFI
1397 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1399 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1400 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1402 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1404 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1405 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1409 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1410 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1413 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1414 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1420 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1422 int len
= GRUB_UINT_MAX
;
1423 const char *value
= NULL
;
1424 char name
[32] = {0};
1425 char plat
[32] = {0};
1426 char guidstr
[32] = {0};
1427 ventoy_guid guid
= VENTOY_GUID
;
1428 const char *fmt1
= NULL
;
1429 const char *fmt2
= NULL
;
1430 const char *fmt3
= NULL
;
1431 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1432 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1433 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1434 const char fmtcode
[]={
1435 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1436 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1437 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1438 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1439 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1440 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1443 grub_memset(name
, 0, sizeof(name
));
1444 puint
[0] = grub_swap_bytes32(0x56454e54);
1445 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1446 puint
[2] = grub_swap_bytes32(0x45525349);
1447 puint
[1] = grub_swap_bytes32(0x4f595f56);
1448 value
= ventoy_get_env(name
);
1450 grub_memset(name
, 0, sizeof(name
));
1451 puint
[1] = grub_swap_bytes32(0x5f544f50);
1452 puint
[0] = grub_swap_bytes32(0x56544c45);
1453 fmt1
= ventoy_get_env(name
);
1459 grub_memset(name
, 0, sizeof(name
));
1460 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1461 puint
[0] = grub_swap_bytes32(0x56544c45);
1462 fmt2
= ventoy_get_env(name
);
1464 grub_memset(name
, 0, sizeof(name
));
1465 puint
[1] = grub_swap_bytes32(0x5f434c52);
1466 puint
[0] = grub_swap_bytes32(0x56544c45);
1467 fmt3
= ventoy_get_env(name
);
1469 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1471 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1473 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1474 #pragma GCC diagnostic push
1475 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1476 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1477 fmt1
? fmt1
: fmtdata
,
1478 fmt2
? fmt2
: fmtdata
+ 4,
1479 value
? value
: "", plat
, guidstr
,
1480 fmt3
? fmt3
: fmtdata
+ 6);
1481 #pragma GCC diagnostic pop
1483 grub_memset(name
, 0, sizeof(name
));
1484 puint
[0] = grub_swap_bytes32(0x76746f79);
1485 puint
[2] = grub_swap_bytes32(0x656e7365);
1486 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1487 ventoy_set_env(name
, guidstr
);
1492 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1496 grub_uint8_t md5
[16];
1500 grub_memset(input
, 0, sizeof(input
));
1502 grub_printf("Enter password: ");
1505 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1507 grub_password_get(input
, 128);
1508 if (grub_strcmp(pwd
->text
, input
) == 0)
1513 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1515 grub_password_get(input
, 128);
1516 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1517 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1522 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1524 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1525 grub_password_get(input
+ offset
, 128);
1527 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1528 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1534 grub_printf("Invalid password!\n\n");
1541 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1543 img_info
*minimg
= NULL
;
1544 img_info
*img
= (img_info
*)(node
->firstiso
);
1546 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1548 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1563 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1565 img_iterator_node
*Minchild
= NULL
;
1566 img_iterator_node
*child
= node
->firstchild
;
1568 while (child
&& child
->parent
== node
)
1570 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1574 child
= child
->next
;
1579 Minchild
->select
= 1;
1585 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1588 img_info
*img
= NULL
;
1589 const char *dir_class
= NULL
;
1590 const char *dir_alias
= NULL
;
1591 img_iterator_node
*child
= NULL
;
1593 if (node
->isocnt
== 0 || node
->done
== 1)
1598 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1600 offset
= node
->parent
->dirlen
;
1603 if (node
== &g_img_iterator_head
)
1605 if (g_default_menu_mode
== 0)
1607 if (g_tree_view_menu_style
== 0)
1609 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1610 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1611 " echo 'return ...' \n"
1616 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1617 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1625 node
->dir
[node
->dirlen
- 1] = 0;
1626 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1629 dir_class
= "vtoydir";
1632 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1635 if (g_tree_view_menu_style
== 0)
1637 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1638 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1639 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1643 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1644 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1645 dir_alias
, dir_class
, node
->dir
+ offset
);
1650 dir_alias
= node
->dir
+ offset
;
1652 if (g_tree_view_menu_style
== 0)
1654 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1655 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1656 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1660 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1661 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1662 dir_alias
, dir_class
, node
->dir
+ offset
);
1666 if (g_tree_view_menu_style
== 0)
1668 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1669 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1670 " echo 'return ...' \n"
1675 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1676 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1682 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1684 ventoy_dynamic_tree_menu(child
);
1687 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1689 if (g_tree_view_menu_style
== 0)
1691 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1692 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1695 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1696 img
->unsupport
? "[***********] " : "",
1697 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1699 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1703 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1704 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1707 img
->unsupport
? "[***********] " : "",
1708 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1710 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1714 if (node
!= &g_img_iterator_head
)
1716 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1723 int ventoy_check_device_result(int ret
)
1727 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1728 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1729 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1733 grub_printf(VTOY_WARNING
"\n");
1734 grub_printf(VTOY_WARNING
"\n");
1735 grub_printf(VTOY_WARNING
"\n\n\n");
1737 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1738 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1740 grub_printf("\n\nWill exit after 10 seconds ...... ");
1748 int ventoy_check_device(grub_device_t dev
)
1752 grub_uint64_t offset
;
1757 struct grub_partition
*partition
;
1759 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1761 return ventoy_check_device_result(1 | 0x1000);
1764 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1765 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1766 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1768 #ifndef GRUB_MACHINE_EFI
1769 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1770 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1771 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1773 return ventoy_check_device_result(2 | 0x1000);
1782 /* We must have partition 2 */
1785 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1789 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1793 return ventoy_check_device_result(3 | 0x1000);
1796 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1798 grub_file_close(file
);
1799 return ventoy_check_device_result(4 | 0x1000);
1802 partition
= dev
->disk
->partition
;
1803 if (partition
->number
!= 0 || partition
->start
!= 2048)
1805 return ventoy_check_device_result(5);
1810 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
1812 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
1813 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
1814 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
1816 grub_file_close(file
);
1817 return ventoy_check_device_result(6);
1822 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1823 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1824 PartTbl
[1].SectorCount
!= 65536)
1826 grub_file_close(file
);
1827 return ventoy_check_device_result(6);
1833 offset
= partition
->start
+ partition
->len
;
1834 partition
= file
->device
->disk
->partition
;
1835 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1837 grub_file_close(file
);
1838 return ventoy_check_device_result(7);
1842 grub_file_close(file
);
1844 if (workaround
== 0)
1846 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1847 dev2
= grub_device_open(devname
);
1850 return ventoy_check_device_result(8);
1853 fs
= grub_fs_probe(dev2
);
1856 grub_device_close(dev2
);
1857 return ventoy_check_device_result(9);
1860 fs
->fs_label(dev2
, &label
);
1861 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1863 grub_device_close(dev2
);
1864 return ventoy_check_device_result(10);
1867 grub_device_close(dev2
);
1870 return ventoy_check_device_result(0);
1873 static int ventoy_set_default_menu(void)
1879 const char *strdata
= NULL
;
1880 img_info
*cur
= NULL
;
1881 img_info
*default_node
= NULL
;
1882 const char *default_image
= NULL
;
1884 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1885 if (default_image
&& default_image
[0] == '/')
1887 img_len
= grub_strlen(default_image
);
1889 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1891 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1903 if (0 == g_default_menu_mode
)
1905 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1909 def
= grub_strdup(default_image
);
1915 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1917 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1918 if (strdata
&& strdata
[0] == '/')
1920 pos
= def
+ grub_strlen(strdata
);
1931 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1934 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1938 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1946 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1950 grub_device_t dev
= NULL
;
1951 img_info
*cur
= NULL
;
1952 img_info
*tail
= NULL
;
1953 const char *strdata
= NULL
;
1954 char *device_name
= NULL
;
1956 img_iterator_node
*node
= NULL
;
1957 img_iterator_node
*tmp
= NULL
;
1963 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1966 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1968 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1971 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1972 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1974 g_filt_dot_underscore_file
= 1;
1977 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1978 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1980 g_sort_case_sensitive
= 1;
1983 device_name
= grub_file_get_device_name(args
[0]);
1989 g_enum_dev
= dev
= grub_device_open(device_name
);
1995 g_enum_fs
= fs
= grub_fs_probe(dev
);
2001 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
2003 debug("unsupported fs:<%s>\n", fs
->name
);
2004 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2008 ventoy_set_env("vtoy_iso_fs", fs
->name
);
2010 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2011 if (strdata
&& strdata
[0] == '1')
2013 g_default_menu_mode
= 1;
2016 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
2018 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
2020 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2021 if (strdata
&& strdata
[0] == '/')
2023 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
2024 if (g_img_iterator_head
.dir
[len
- 1] != '/')
2026 g_img_iterator_head
.dir
[len
++] = '/';
2028 g_img_iterator_head
.dirlen
= len
;
2032 g_img_iterator_head
.dirlen
= 1;
2033 grub_strcpy(g_img_iterator_head
.dir
, "/");
2036 g_img_iterator_head
.tail
= &tail
;
2038 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2040 fs
->fs_dir(dev
, node
->dir
, ventoy_collect_img_files
, node
);
2043 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2044 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2046 g_tree_view_menu_style
= 1;
2049 ventoy_set_default_menu();
2051 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2053 ventoy_dynamic_tree_menu(node
);
2057 node
= g_img_iterator_head
.next
;
2065 /* sort image list by image name */
2066 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2068 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2070 if (ventoy_cmp_img(cur
, tail
) > 0)
2072 ventoy_swap_img(cur
, tail
);
2077 if (g_default_menu_mode
== 1)
2079 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2080 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2081 " echo 'return ...' \n"
2085 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2087 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2088 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2091 cur
->unsupport
? "[***********] " : "",
2092 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2094 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2097 g_tree_script_buf
[g_tree_script_pos
] = 0;
2098 g_list_script_buf
[g_list_script_pos
] = 0;
2100 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2101 grub_env_set(args
[1], buf
);
2105 check_free(device_name
, grub_free
);
2106 check_free(dev
, grub_device_close
);
2108 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2112 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2114 img_info
*next
= NULL
;
2115 img_info
*cur
= g_ventoy_img_list
;
2128 g_ventoy_img_list
= NULL
;
2129 g_ventoy_img_count
= 0;
2131 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2134 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2137 img_info
*cur
= g_ventoy_img_list
;
2141 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2143 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2146 img_id
= grub_strtol(args
[0], NULL
, 10);
2147 if (img_id
>= g_ventoy_img_count
)
2149 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2152 debug("Find image %ld name \n", img_id
);
2154 while (cur
&& img_id
> 0)
2162 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2165 debug("image name is %s\n", cur
->name
);
2167 grub_env_set(args
[1], cur
->name
);
2169 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2172 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2177 const char *id
= NULL
;
2178 img_info
*cur
= g_ventoy_img_list
;
2182 if (argc
< 1 || argc
> 2)
2184 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2187 id
= grub_env_get("chosen");
2189 pos
= grub_strstr(id
, "VID_");
2192 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2196 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2201 if (img_id
== cur
->id
)
2210 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2213 grub_env_set(args
[0], cur
->path
);
2217 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2218 grub_env_set(args
[1], value
);
2221 g_svd_replace_offset
= 0;
2223 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2226 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2233 device_name
= grub_file_get_device_name(filename
);
2245 pos2
= grub_strstr(pos
, ",");
2248 pos2
= grub_strstr(pos
, ")");
2256 disk
= grub_disk_open(pos
);
2259 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2260 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2261 grub_disk_close(disk
);
2268 grub_free(device_name
);
2272 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2274 eltorito_descriptor desc
;
2276 grub_memset(&desc
, 0, sizeof(desc
));
2277 grub_file_seek(file
, 17 * 2048);
2278 grub_file_read(file
, &desc
, sizeof(desc
));
2280 if (desc
.type
!= 0 || desc
.version
!= 1)
2285 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2286 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2294 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2298 grub_uint8_t buf
[512];
2299 grub_uint8_t parttype
[] = { 0x04, 0x06, 0x0B, 0x0C };
2301 grub_file_seek(file
, sector
* 2048);
2302 grub_file_read(file
, buf
, sizeof(buf
));
2304 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2306 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2310 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2315 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2317 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2319 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2323 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2325 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2330 if (x86count
&& buf
[32] == 0x88 && buf
[33] == 0x04)
2332 for (i
= 0; i
< (int)(ARRAY_SIZE(parttype
)); i
++)
2334 if (buf
[36] == parttype
[i
])
2336 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file
->name
, buf
[36]);
2342 debug("%s does not contain efi eltorito\n", file
->name
);
2346 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2349 const char *fs
= NULL
;
2350 const char *cdprompt
= NULL
;
2352 grub_uint8_t chksum
= 0;
2355 disk
= file
->device
->disk
;
2356 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2358 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2359 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2360 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2362 pos
= grub_strstr(file
->name
, "/");
2368 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2370 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2372 param
->vtoy_img_size
= file
->size
;
2374 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2375 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2377 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2379 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2380 param
->vtoy_reserved
[4] = 0;
2381 if (g_ventoy_chain_type
== 1) /* Windows */
2383 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2384 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2386 param
->vtoy_reserved
[4] = 1;
2390 fs
= ventoy_get_env("ventoy_fs_probe");
2391 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2393 param
->vtoy_reserved
[3] = 1;
2396 /* calculate checksum */
2397 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2399 chksum
+= *((grub_uint8_t
*)param
+ i
);
2401 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2406 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2408 grub_uint32_t i
= 0;
2409 grub_uint64_t total
= 0;
2410 ventoy_img_chunk
*chunk
= NULL
;
2412 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2414 chunk
= chunklist
->chunk
+ i
;
2416 if (chunk
->disk_start_sector
<= start
)
2418 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2422 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2425 if (total
!= ((file
->size
+ 511) / 512))
2427 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2434 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2438 grub_uint32_t i
= 0;
2439 grub_uint32_t sector
= 0;
2440 grub_uint32_t count
= 0;
2441 grub_off_t size
= 0;
2442 grub_off_t read
= 0;
2444 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2445 if (fs_type
== ventoy_fs_exfat
)
2447 grub_fat_get_file_chunk(start
, file
, chunklist
);
2449 else if (fs_type
== ventoy_fs_ext
)
2451 grub_ext_get_file_chunk(start
, file
, chunklist
);
2455 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2456 file
->read_hook_data
= chunklist
;
2458 for (size
= file
->size
; size
> 0; size
-= read
)
2460 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2461 grub_file_read(file
, NULL
, read
);
2464 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2466 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2467 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2470 if (ventoy_fs_udf
== fs_type
)
2472 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2474 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2475 chunklist
->chunk
[i
].img_start_sector
= sector
;
2476 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2482 len
= (int)grub_strlen(file
->name
);
2483 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2484 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2485 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2486 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2488 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2490 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2500 chunklist
->chunk
[i
].img_start_sector
= sector
;
2501 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2509 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2513 grub_disk_addr_t start
;
2518 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2521 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2524 g_conf_replace_node
= NULL
;
2525 g_conf_replace_offset
= 0;
2527 if (g_img_chunk_list
.chunk
)
2529 grub_free(g_img_chunk_list
.chunk
);
2532 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2534 grub_file_close(file
);
2535 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2538 /* get image chunk data */
2539 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2540 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2541 if (NULL
== g_img_chunk_list
.chunk
)
2543 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2546 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2547 g_img_chunk_list
.cur_chunk
= 0;
2549 start
= file
->device
->disk
->partition
->start
;
2551 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2553 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2554 grub_file_close(file
);
2558 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2561 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2562 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2565 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2567 grub_uint64_t offset
= 0;
2568 grub_uint32_t align
= 0;
2569 grub_file_t file
= NULL
;
2570 conf_replace
*node
= NULL
;
2576 debug("select conf replace argc:%d\n", argc
);
2583 node
= ventoy_plugin_find_conf_replace(args
[1]);
2586 debug("Conf replace not found for %s\n", args
[1]);
2590 debug("Find conf replace for %s\n", args
[1]);
2592 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2595 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2599 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2600 grub_file_close(file
);
2602 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2605 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2609 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2611 if (align
> vtoy_max_replace_file_size
)
2613 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2617 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2618 g_conf_replace_new_len
= (int)file
->size
;
2619 g_conf_replace_new_len_align
= align
;
2621 g_conf_replace_node
= node
;
2622 g_conf_replace_offset
= offset
+ 2;
2624 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2629 grub_file_close(file
);
2631 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2634 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2639 char configfile
[128];
2640 install_template
*node
= NULL
;
2646 debug("select auto installation argc:%d\n", argc
);
2653 node
= ventoy_plugin_find_install_template(args
[0]);
2656 debug("Auto install template not found for %s\n", args
[0]);
2660 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2662 node
->cursel
= node
->autosel
- 1;
2663 debug("Auto install template auto select %d\n", node
->autosel
);
2667 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2673 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2674 " echo %s\n}\n", "123");
2676 for (i
= 0; i
< node
->templatenum
; i
++)
2678 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2680 node
->templatepath
[i
].path
);
2683 g_ventoy_menu_esc
= 1;
2684 g_ventoy_suppress_esc
= 1;
2686 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2687 grub_script_execute_sourcecode(configfile
);
2689 g_ventoy_menu_esc
= 0;
2690 g_ventoy_suppress_esc
= 0;
2694 node
->cursel
= g_ventoy_last_entry
- 1;
2696 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2699 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2704 char configfile
[128];
2705 persistence_config
*node
;
2711 debug("select persistence argc:%d\n", argc
);
2718 node
= ventoy_plugin_find_persistent(args
[0]);
2721 debug("Persistence image not found for %s\n", args
[0]);
2725 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2727 node
->cursel
= node
->autosel
- 1;
2728 debug("Persistence image auto select %d\n", node
->autosel
);
2732 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2738 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2739 " echo %s\n}\n", "123");
2741 for (i
= 0; i
< node
->backendnum
; i
++)
2743 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2745 node
->backendpath
[i
].path
);
2749 g_ventoy_menu_esc
= 1;
2750 g_ventoy_suppress_esc
= 1;
2752 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2753 grub_script_execute_sourcecode(configfile
);
2755 g_ventoy_menu_esc
= 0;
2756 g_ventoy_suppress_esc
= 0;
2760 node
->cursel
= g_ventoy_last_entry
- 1;
2762 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2765 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2768 ventoy_img_chunk
*cur
;
2774 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2776 cur
= g_img_chunk_list
.chunk
+ i
;
2777 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2778 cur
->img_start_sector
, cur
->img_end_sector
,
2779 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2783 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2786 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2790 ventoy_img_chunk_list chunklist
;
2795 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2798 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2801 /* get image chunk data */
2802 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2803 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2804 if (NULL
== chunklist
.chunk
)
2806 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2809 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2810 chunklist
.cur_chunk
= 0;
2812 ventoy_get_block_list(file
, &chunklist
, 0);
2814 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2816 grub_printf("########## UNSUPPORTED ###############\n");
2819 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2821 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2823 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2824 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2827 grub_printf("\n==================================\n");
2829 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2831 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2832 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2833 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2834 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2835 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2839 grub_free(chunklist
.chunk
);
2840 grub_file_close(file
);
2842 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2845 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2848 ventoy_grub_param_file_replace
*replace
= NULL
;
2856 replace
= &(g_grub_param
->file_replace
);
2857 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2859 replace
->old_name_cnt
= 0;
2860 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2862 replace
->old_name_cnt
++;
2863 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2866 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2869 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2872 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2880 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2881 grub_printf("%s", g_list_script_buf
);
2885 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2886 grub_printf("%s", g_tree_script_buf
);
2892 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2894 img_info
*cur
= g_ventoy_img_list
;
2902 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2903 grub_printf("name:<%s>\n\n", cur
->name
);
2910 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2916 ventoy_plugin_dump_injection();
2921 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2927 ventoy_plugin_dump_auto_install();
2932 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2938 ventoy_plugin_dump_persistence();
2943 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2954 if (args
[0][0] == '0')
2956 return g_ventoy_memdisk_mode
? 0 : 1;
2958 else if (args
[0][0] == '1')
2960 return g_ventoy_iso_raw
? 0 : 1;
2962 else if (args
[0][0] == '2')
2964 return g_ventoy_iso_uefi_drv
? 0 : 1;
2970 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2972 static int configfile_mode
= 0;
2973 char memfile
[128] = {0};
2980 * args[0]: 0:normal 1:configfile
2981 * args[1]: 0:list_buf 1:tree_buf
2986 debug("Invalid argc %d\n", argc
);
2990 if (args
[0][0] == '0')
2992 if (args
[1][0] == '0')
2994 grub_script_execute_sourcecode(g_list_script_buf
);
2998 grub_script_execute_sourcecode(g_tree_script_buf
);
3003 if (configfile_mode
)
3005 debug("Now already in F3 mode %d\n", configfile_mode
);
3009 if (args
[1][0] == '0')
3011 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3012 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
3016 g_ventoy_last_entry
= -1;
3017 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3018 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
3021 configfile_mode
= 1;
3022 grub_script_execute_sourcecode(memfile
);
3023 configfile_mode
= 0;
3029 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3040 g_ventoy_case_insensitive
= 1;
3041 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
3042 g_ventoy_case_insensitive
= 0;
3048 grub_file_close(file
);
3054 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3059 const char *isopath
= NULL
;
3061 ventoy_mbr_head mbr
;
3068 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3071 isopath
= grub_env_get("vtoy_iso_part");
3074 debug("isopath is null %p\n", isopath
);
3078 debug("isopath is %s\n", isopath
);
3080 for (id
= 0; id
< 30 && (find
== 0); id
++)
3082 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3083 if (grub_strstr(isopath
, hdname
))
3085 debug("skip %s ...\n", hdname
);
3089 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3091 disk
= grub_disk_open(hdname
);
3094 debug("%s not exist\n", hdname
);
3098 grub_memset(&mbr
, 0, sizeof(mbr
));
3099 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3101 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3103 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3104 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3107 grub_env_set(args
[0], hdname
);
3111 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3115 debug("read %s failed\n", hdname
);
3118 grub_disk_close(disk
);
3124 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3135 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3138 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3141 debug("failed to open file %s\n", args
[0]);
3145 buf
= grub_malloc(len
);
3152 grub_file_read(file
, buf
, len
- 1);
3154 ventoy_get_line(buf
);
3155 ventoy_set_env(args
[1], buf
);
3159 grub_check_free(buf
);
3160 grub_file_close(file
);
3165 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3170 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3171 "0 %llu linear /dev/ventoy %llu\n",
3172 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3177 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3179 char *device_name
= NULL
;
3180 grub_device_t dev
= NULL
;
3185 g_part_list_pos
= 0;
3186 grub_env_unset("vtoy_img_part_file");
3193 device_name
= grub_file_get_device_name(args
[0]);
3196 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3200 dev
= grub_device_open(device_name
);
3203 debug("grub_device_open failed, %s\n", device_name
);
3207 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3209 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3210 grub_env_set("vtoy_img_part_file", buf
);
3214 check_free(device_name
, grub_free
);
3215 check_free(dev
, grub_device_close
);
3221 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3232 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3235 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3238 debug("failed to open file %s\n", args
[0]);
3242 buf
= grub_malloc(file
->size
+ 1);
3248 buf
[file
->size
] = 0;
3249 grub_file_read(file
, buf
, file
->size
);
3251 if (grub_strstr(buf
, args
[1]))
3258 grub_check_free(buf
);
3259 grub_file_close(file
);
3264 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3270 ventoy_iso9660_vd pvd
;
3277 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid space \n", cmd_raw_name
);
3280 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3283 debug("failed to open file %s\n", args
[0]);
3287 grub_file_seek(file
, 16 * 2048);
3288 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3289 if (len
!= sizeof(pvd
))
3291 debug("failed to read pvd %d\n", len
);
3295 grub_memset(buf
, 0, sizeof(buf
));
3296 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3297 ventoy_set_env(args
[1], buf
);
3299 grub_memset(buf
, 0, sizeof(buf
));
3300 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3301 ventoy_set_env(args
[2], buf
);
3305 grub_snprintf(buf
, sizeof(buf
), "%llu", (ulonglong
)size
);
3306 ventoy_set_env(args
[3], buf
);
3309 grub_file_close(file
);
3314 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3325 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3328 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3331 debug("failed to open file %s\n", args
[0]);
3335 grub_memset(buf
, 0, sizeof(buf
));
3336 grub_file_seek(file
, 16 * 2048 + 813);
3337 len
= (int)grub_file_read(file
, buf
, 17);
3340 debug("failed to read create date %d\n", len
);
3344 ventoy_set_env(args
[1], buf
);
3347 grub_file_close(file
);
3352 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3358 ventoy_env_hook_root(1);
3363 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3369 ventoy_env_hook_root(0);
3374 #ifdef GRUB_MACHINE_EFI
3375 static grub_err_t
ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3380 grub_efi_guid_t global
= GRUB_EFI_GLOBAL_VARIABLE_GUID
;
3386 var
= grub_efi_get_variable("SecureBoot", &global
, &size
);
3387 if (var
&& *var
== 1)
3395 static grub_err_t
ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3404 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3411 int image_sector_size
;
3413 ventoy_chain_head
*chain
;
3414 ventoy_img_chunk
*chunk
;
3415 ventoy_os_param
*osparam
;
3416 ventoy_image_location
*location
;
3417 ventoy_image_disk_region
*region
;
3418 struct grub_acpi_table_header
*acpi
;
3427 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3429 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3435 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3437 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3439 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3443 img_chunk_num
= chain
->img_chunk_num
;
3445 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3446 datalen
= sizeof(ventoy_os_param
) + loclen
;
3448 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3449 acpi
= grub_zalloc(buflen
);
3455 /* Step1: Fill acpi table header */
3456 grub_memcpy(acpi
->signature
, "VTOY", 4);
3457 acpi
->length
= buflen
;
3459 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3460 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3462 acpi
->creator_id
[0] = 1;
3463 acpi
->creator_rev
= 1;
3465 /* Step2: Fill data */
3466 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3467 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3468 osparam
->vtoy_img_location_addr
= 0;
3469 osparam
->vtoy_img_location_len
= loclen
;
3470 osparam
->chksum
= 0;
3471 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3473 location
= (ventoy_image_location
*)(osparam
+ 1);
3474 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3475 location
->image_sector_size
= image_sector_size
;
3476 location
->disk_sector_size
= chain
->disk_sector_size
;
3477 location
->region_count
= img_chunk_num
;
3479 region
= location
->regions
;
3480 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3481 if (512 == image_sector_size
)
3483 for (i
= 0; i
< img_chunk_num
; i
++)
3485 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3486 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3487 region
->disk_start_sector
= chunk
->disk_start_sector
;
3494 for (i
= 0; i
< img_chunk_num
; i
++)
3496 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3497 region
->image_start_sector
= chunk
->img_start_sector
;
3498 region
->disk_start_sector
= chunk
->disk_start_sector
;
3504 /* Step3: Fill acpi checksum */
3506 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3508 /* load acpi table */
3509 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3510 grub_script_execute_sourcecode(cmd
);
3514 VENTOY_CMD_RETURN(0);
3517 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3523 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3524 g_ventoy_last_entry
= -1;
3529 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3535 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3540 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3542 grub_uint64_t sectors
;
3544 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3546 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3550 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3553 return sectors
* 512;
3556 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3558 const char *pos
= filename
+ 1;
3566 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3568 grub_strncpy((char *)data
, filename
, 128);
3579 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3582 char *device_name
= NULL
;
3583 grub_device_t dev
= NULL
;
3584 grub_fs_t fs
= NULL
;
3585 char buf
[128] = {0};
3591 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3595 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3597 device_name
= grub_file_get_device_name(args
[0]);
3600 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3604 dev
= grub_device_open(device_name
);
3607 debug("grub_device_open failed, %s\n", device_name
);
3611 fs
= grub_fs_probe(dev
);
3614 debug("grub_fs_probe failed, %s\n", device_name
);
3618 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3622 ventoy_set_env(args
[2], buf
);
3629 check_free(device_name
, grub_free
);
3630 check_free(dev
, grub_device_close
);
3635 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3645 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3646 if (!g_ventoy_part_info
)
3651 disk
= grub_disk_open(args
[0]);
3654 debug("Failed to open disk %s\n", args
[0]);
3658 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3660 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3661 grub_disk_close(disk
);
3663 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3664 dev
= grub_device_open(name
);
3667 /* make sure that we are running in a correct Ventoy device */
3668 ret
= ventoy_check_device(dev
);
3669 grub_device_close(dev
);
3680 static grub_err_t
ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3683 const char *vcfg
= NULL
;
3688 vcfg
= ventoy_plugin_get_custom_boot(args
[0]);
3691 debug("custom boot <%s>:<%s>\n", args
[0], vcfg
);
3692 grub_env_set(args
[1], vcfg
);
3697 debug("custom boot <%s>:<NOT FOUND>\n", args
[0]);
3705 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3708 grub_uint8_t zeroguid
[16] = {0};
3713 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3716 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3718 if (id
>= 1 && id
<= 128)
3720 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3728 if (id
>= 1 && id
<= 4)
3730 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3740 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3743 char *device_name
= NULL
;
3744 grub_device_t dev
= NULL
;
3745 grub_fs_t fs
= NULL
;
3752 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3756 device_name
= grub_file_get_device_name(args
[0]);
3759 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3763 dev
= grub_device_open(device_name
);
3766 debug("grub_device_open failed, %s\n", device_name
);
3770 fs
= grub_fs_probe(dev
);
3773 debug("grub_fs_probe failed, %s\n", device_name
);
3777 fs
->fs_label(dev
, &label
);
3780 ventoy_set_env(args
[1], label
);
3788 check_free(device_name
, grub_free
);
3789 check_free(dev
, grub_device_close
);
3794 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3798 grub_snprintf((char *)data
, 256, "%s", filename
);
3806 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3809 char *device_name
= NULL
;
3810 grub_device_t dev
= NULL
;
3811 grub_fs_t fs
= NULL
;
3812 char name
[256] ={0};
3818 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3822 device_name
= grub_file_get_device_name(args
[0]);
3825 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3829 dev
= grub_device_open(device_name
);
3832 debug("grub_device_open failed, %s\n", device_name
);
3836 fs
= grub_fs_probe(dev
);
3839 debug("grub_fs_probe failed, %s\n", device_name
);
3843 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3846 ventoy_set_env(args
[2], name
);
3853 check_free(device_name
, grub_free
);
3854 check_free(dev
, grub_device_close
);
3859 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3869 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3873 for (pos
= args
[0]; *pos
; pos
++)
3887 grub_env_set(args
[1], args
[0]);
3897 static grub_err_t
ventoy_cmd_basefile(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3907 debug("ventoy_cmd_basefile, invalid param num %d\n", argc
);
3912 len
= (int)grub_strlen(buf
);
3913 for (i
= len
; i
> 0; i
--)
3915 if (buf
[i
- 1] == '/')
3917 grub_env_set(args
[1], buf
+ i
);
3922 grub_env_set(args
[1], buf
);
3927 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3929 struct grub_video_mode_info info
;
3936 if (!g_video_mode_list
)
3938 ventoy_enum_video_mode();
3941 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3943 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3947 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3950 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3952 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3953 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3955 VENTOY_CMD_RETURN(0);
3958 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3960 struct grub_video_mode_info info
;
3967 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3969 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3973 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3976 grub_env_set(args
[0], buf
);
3978 VENTOY_CMD_RETURN(0);
3981 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3989 if (!g_video_mode_list
)
3994 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3995 if (id
< g_video_mode_num
)
3997 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3998 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
4001 grub_env_set(args
[1], buf
);
4003 VENTOY_CMD_RETURN(0);
4006 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
4008 grub_uint64_t size
= 0;
4011 char fullpath
[256] = {0};
4014 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
4017 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
4020 debug("grub_file_open failed <%s>\n", fullpath
);
4026 grub_file_close(file
);
4030 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
4034 char fullpath
[256] = {0};
4037 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
4040 file
= grub_file_open(fullpath
, type
);
4043 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
4050 int ventoy_is_file_exist(const char *fmt
, ...)
4055 char buf
[256] = {0};
4057 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
4061 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
4064 grub_strncpy(pos
+ len
, "\" ]", 3);
4066 debug("script exec %s\n", buf
);
4068 if (0 == grub_script_execute_sourcecode(buf
))
4076 int ventoy_is_dir_exist(const char *fmt
, ...)
4081 char buf
[256] = {0};
4083 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
4087 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
4090 grub_strncpy(pos
+ len
, "\" ]", 3);
4092 debug("script exec %s\n", buf
);
4094 if (0 == grub_script_execute_sourcecode(buf
))
4102 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
4105 grub_uint8_t
*outbuf
;
4106 grub_uint8_t gzHdr
[10] =
4108 0x1F, 0x8B, /* magic */
4111 0,0,0,0, /* mtime */
4116 grub_memset(&s
, 0, sizeof(mz_stream
));
4118 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
4120 outbuf
= (grub_uint8_t
*)mem_out
;
4122 mem_out_len
-= sizeof(gzHdr
) + 8;
4123 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
4124 outbuf
+= sizeof(gzHdr
);
4126 s
.avail_in
= mem_in_len
;
4129 s
.avail_out
= mem_out_len
;
4130 s
.next_out
= outbuf
;
4132 mz_deflate(&s
, MZ_FINISH
);
4136 outbuf
+= s
.total_out
;
4137 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
4138 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
4140 return s
.total_out
+ sizeof(gzHdr
) + 8;
4143 static int ventoy_env_init(void)
4147 grub_env_set("vtdebug_flag", "");
4149 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4150 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4151 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4152 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4154 ventoy_filt_register(0, ventoy_wrapper_open
);
4156 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4159 g_grub_param
->grub_env_get
= grub_env_get
;
4160 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4161 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4162 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4163 grub_env_set("env_param", buf
);
4164 grub_env_set("ventoy_env_param", buf
);
4165 grub_env_export("ventoy_env_param");
4171 static cmd_para ventoy_cmds
[] =
4173 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4174 { "vt_mod", ventoy_cmd_mod
, 0, NULL
, "{Int} {Int} {Var}", "mod integer variable", NULL
},
4175 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4176 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4177 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4178 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4179 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4180 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4181 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4182 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4183 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4184 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4185 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4186 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4187 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4188 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4189 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4190 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4191 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4192 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4193 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4194 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot
, 0, NULL
, "", "", NULL
},
4195 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot
, 0, NULL
, "", "", NULL
},
4197 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4198 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4199 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4200 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4201 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4202 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4203 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4205 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4206 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4207 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4208 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4209 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4210 { "vt_file_basefile", ventoy_cmd_basefile
, 0, NULL
, "", "", NULL
},
4211 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4212 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4213 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4216 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4217 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4218 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4219 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4220 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4221 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4222 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4223 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4224 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4225 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4226 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4228 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4229 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4230 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4231 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4232 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4233 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4235 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4236 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4237 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4238 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4239 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4240 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4241 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4242 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4243 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4244 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4246 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4247 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4248 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4249 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4250 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4251 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4252 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4253 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4255 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4256 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4257 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4260 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4261 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4262 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4264 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4265 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4266 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4269 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4270 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4271 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4272 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4273 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4274 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4275 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4276 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4277 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4278 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4280 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4281 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4282 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4283 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var
, 0, NULL
, "", "", NULL
},
4289 GRUB_MOD_INIT(ventoy
)
4292 cmd_para
*cur
= NULL
;
4296 ventoy_arch_mode_init();
4298 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4300 cur
= ventoy_cmds
+ i
;
4301 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4302 cur
->summary
, cur
->description
, cur
->parser
);
4306 GRUB_MOD_FINI(ventoy
)
4310 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4312 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);