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/efi.h>
41 #include <grub/time.h>
42 #include <grub/video.h>
43 #include <grub/acpi.h>
44 #include <grub/charset.h>
45 #include <grub/crypto.h>
46 #include <grub/lib/crc.h>
47 #include <grub/ventoy.h>
48 #include "ventoy_def.h"
51 GRUB_MOD_LICENSE ("GPLv3+");
53 int g_ventoy_debug
= 0;
54 static int g_efi_os
= 0xFF;
55 initrd_info
*g_initrd_img_list
= NULL
;
56 initrd_info
*g_initrd_img_tail
= NULL
;
57 int g_initrd_img_count
= 0;
58 int g_valid_initrd_count
= 0;
59 int g_default_menu_mode
= 0;
60 int g_filt_dot_underscore_file
= 0;
61 int g_sort_case_sensitive
= 0;
62 int g_tree_view_menu_style
= 0;
63 static grub_file_t g_old_file
;
64 static int g_ventoy_last_entry_back
;
65 static grub_uint32_t g_ventoy_plat_data
;
68 char g_img_swap_tmp_buf
[1024];
69 img_info g_img_swap_tmp
;
70 img_info
*g_ventoy_img_list
= NULL
;
72 int g_ventoy_img_count
= 0;
74 grub_device_t g_enum_dev
= NULL
;
75 grub_fs_t g_enum_fs
= NULL
;
76 img_iterator_node g_img_iterator_head
;
77 img_iterator_node
*g_img_iterator_tail
= NULL
;
79 grub_uint8_t g_ventoy_break_level
= 0;
80 grub_uint8_t g_ventoy_debug_level
= 0;
81 grub_uint8_t g_ventoy_chain_type
= 0;
83 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
84 grub_uint32_t g_ventoy_cpio_size
= 0;
85 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
86 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
88 int g_plugin_image_list
= 0;
90 ventoy_grub_param
*g_grub_param
= NULL
;
92 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
94 ventoy_img_chunk_list g_img_chunk_list
;
96 int g_wimboot_enable
= 0;
97 ventoy_img_chunk_list g_wimiso_chunk_list
;
98 char *g_wimiso_path
= NULL
;
100 int g_vhdboot_enable
= 0;
102 grub_uint64_t g_conf_replace_offset
= 0;
103 grub_uint64_t g_svd_replace_offset
= 0;
104 conf_replace
*g_conf_replace_node
= NULL
;
105 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
106 int g_conf_replace_new_len
= 0;
107 int g_conf_replace_new_len_align
= 0;
109 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
110 grub_uint64_t g_ventoy_disk_size
= 0;
112 static char *g_tree_script_buf
= NULL
;
113 static int g_tree_script_pos
= 0;
115 static char *g_list_script_buf
= NULL
;
116 static int g_list_script_pos
= 0;
118 static char *g_part_list_buf
= NULL
;
119 static int g_part_list_pos
= 0;
121 static int g_video_mode_max
= 0;
122 static int g_video_mode_num
= 0;
123 static ventoy_video_mode
*g_video_mode_list
= NULL
;
125 static const char *g_menu_class
[] =
127 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
130 static const char *g_menu_prefix
[] =
132 "iso", "wim", "efi", "img", "vhd", "vtoy"
135 void ventoy_debug(const char *fmt
, ...)
139 va_start (args
, fmt
);
140 grub_vprintf (fmt
, args
);
144 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
154 for (i
= 0; i
< 16; i
++)
156 grub_printf("%02x ", guid
[i
]);
161 int ventoy_is_efi_os(void)
165 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
171 static int ventoy_get_fs_type(const char *fs
)
175 return ventoy_fs_max
;
177 else if (grub_strncmp(fs
, "exfat", 5) == 0)
179 return ventoy_fs_exfat
;
181 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
183 return ventoy_fs_ntfs
;
185 else if (grub_strncmp(fs
, "ext", 3) == 0)
187 return ventoy_fs_ext
;
189 else if (grub_strncmp(fs
, "xfs", 3) == 0)
191 return ventoy_fs_xfs
;
193 else if (grub_strncmp(fs
, "udf", 3) == 0)
195 return ventoy_fs_udf
;
197 else if (grub_strncmp(fs
, "fat", 3) == 0)
199 return ventoy_fs_fat
;
202 return ventoy_fs_max
;
205 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
224 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
226 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
230 static grub_err_t
ventoy_fs_close(grub_file_t file
)
232 grub_file_close(g_old_file
);
233 grub_free(file
->data
);
241 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
247 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
252 for (i
= 0; i
< g_video_mode_num
; i
++)
254 if (g_video_mode_list
[i
].width
== info
->width
&&
255 g_video_mode_list
[i
].height
== info
->height
&&
256 g_video_mode_list
[i
].bpp
== info
->bpp
)
262 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
263 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
264 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
267 if (g_video_mode_num
== g_video_mode_max
)
269 g_video_mode_max
*= 2;
270 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
276 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
278 if (v1
->bpp
== v2
->bpp
)
280 if (v1
->width
== v2
->width
)
282 if (v1
->height
== v2
->height
)
288 return (v1
->height
< v2
->height
) ? -1 : 1;
293 return (v1
->width
< v2
->width
) ? -1 : 1;
298 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
302 static int ventoy_enum_video_mode(void)
305 grub_video_adapter_t adapter
;
306 grub_video_driver_id_t id
;
307 ventoy_video_mode mode
;
309 g_video_mode_num
= 0;
310 g_video_mode_max
= 1024;
311 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
312 if (!g_video_mode_list
)
317 #ifdef GRUB_MACHINE_PCBIOS
318 grub_dl_load ("vbe");
321 id
= grub_video_get_driver_id ();
323 FOR_VIDEO_ADAPTERS (adapter
)
325 if (!adapter
->iterate
||
326 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
327 adapter
->init() != GRUB_ERR_NONE
)))
332 adapter
->iterate(ventoy_video_hook
, NULL
);
334 if (adapter
->id
!= id
)
340 /* sort video mode */
341 for (i
= 0; i
< g_video_mode_num
; i
++)
342 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
344 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
346 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
347 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
348 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
352 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
355 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
359 static struct grub_fs vtoy_fs
=
364 .fs_read
= ventoy_fs_read
,
365 .fs_close
= ventoy_fs_close
,
375 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
381 file
->data
= grub_malloc(rawFile
->size
+ 4096);
387 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
388 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
390 g_old_file
= rawFile
;
392 file
->size
= rawFile
->size
+ len
;
393 file
->device
= rawFile
->device
;
395 file
->not_easily_seekable
= 1;
400 static int ventoy_check_decimal_var(const char *name
, long *value
)
402 const char *value_str
= NULL
;
404 value_str
= grub_env_get(name
);
405 if (NULL
== value_str
)
407 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
410 if (!ventoy_is_decimal(value_str
))
412 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
415 *value
= grub_strtol(value_str
, NULL
, 10);
417 return GRUB_ERR_NONE
;
420 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
424 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
427 if (0 == grub_strcmp(args
[0], "on"))
430 grub_env_set("vtdebug_flag", "debug");
435 grub_env_set("vtdebug_flag", "");
438 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
441 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
445 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
447 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
448 grub_printf(" level:\r\n");
449 grub_printf(" 01/11: busybox / (+cat log)\r\n");
450 grub_printf(" 02/12: initrd / (+cat log)\r\n");
451 grub_printf(" 03/13: hook / (+cat log)\r\n");
453 grub_printf(" debug:\r\n");
454 grub_printf(" 0: debug is off\r\n");
455 grub_printf(" 1: debug is on\r\n");
457 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
460 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
462 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
464 g_ventoy_debug_level
= 1;
467 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
470 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
479 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
482 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
514 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
519 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
521 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
524 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
529 value_long
+= grub_strtol(args
[1], NULL
, 10);
531 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
532 grub_env_set(args
[0], buf
);
534 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
537 static grub_err_t
ventoy_cmd_mod(grub_extcmd_context_t ctxt
, int argc
, char **args
)
545 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name
);
548 value1
= grub_strtol(args
[0], NULL
, 10);
549 value2
= grub_strtol(args
[1], NULL
, 10);
551 grub_snprintf(buf
, sizeof(buf
), "%ld", (value1
% value2
));
552 grub_env_set(args
[2], buf
);
554 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
557 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
572 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
575 debug("failed to open file <%s> for udf check\n", args
[0]);
579 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
581 grub_env_set(args
[1], buf
);
583 grub_file_close(file
);
589 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
597 g_wimboot_enable
= 0;
598 grub_check_free(g_wimiso_path
);
599 grub_check_free(g_wimiso_chunk_list
.chunk
);
601 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
607 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
608 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
609 if (NULL
== g_wimiso_chunk_list
.chunk
)
611 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
614 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
615 g_wimiso_chunk_list
.cur_chunk
= 0;
617 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
619 g_wimboot_enable
= 1;
620 g_wimiso_path
= grub_strdup(args
[0]);
622 grub_file_close(file
);
627 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
633 grub_uint32_t offset
;
635 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
638 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
642 len
= (int)file
->size
;
644 data
= (char *)grub_malloc(file
->size
);
650 grub_file_read(file
, data
, file
->size
);
651 grub_file_close(file
);
653 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
654 grub_script_execute_sourcecode(exec
);
656 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
657 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
658 grub_file_close(file
);
660 grub_script_execute_sourcecode("loopback -d efiboot");
664 *direntoff
= offset
+ 2;
669 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
679 ventoy_iso9660_override
*dirent
;
688 totlen
= sizeof(ventoy_chain_head
);
690 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
692 debug("failed to load efiboot template %d\n", len
);
698 debug("efiboot template len:%d offset:%d\n", len
, offset
);
700 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
703 debug("failed to open file <%s>\n", args
[0]);
707 totlen
+= ventoy_align_2k(file
->size
);
709 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
710 dirent
->first_sector
= len
/ 2048;
711 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
712 dirent
->size
= (grub_uint32_t
)file
->size
;
713 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
715 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
717 #ifdef GRUB_MACHINE_EFI
718 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
720 data
= (char *)grub_malloc(totlen
);
723 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
725 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
726 grub_check_free(buf
);
728 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
729 grub_file_close(file
);
731 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
732 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
733 grub_env_set(name
, value
);
735 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
736 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
737 grub_env_set(name
, value
);
742 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
759 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
762 debug("failed to open file <%s>\n", args
[0]);
766 #ifdef GRUB_MACHINE_EFI
767 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
769 buf
= (char *)grub_malloc(file
->size
);
772 grub_file_read(file
, buf
, file
->size
);
774 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
775 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
776 grub_env_set(name
, value
);
778 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
779 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
780 grub_env_set(name
, value
);
782 grub_file_close(file
);
788 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
806 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
809 debug("failed to open file <%s> for udf check\n", args
[0]);
813 headlen
= sizeof(ventoy_chain_head
);
815 #ifdef GRUB_MACHINE_EFI
816 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
818 buf
= (char *)grub_malloc(headlen
+ file
->size
);
821 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
823 grub_file_read(file
, buf
+ headlen
, file
->size
);
825 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
826 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
827 grub_env_set(name
, value
);
829 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
830 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
831 grub_env_set(name
, value
);
833 grub_file_close(file
);
839 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
848 if (args
[0][0] == '1')
850 grub_iso9660_set_nojoliet(1);
854 grub_iso9660_set_nojoliet(0);
860 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
865 grub_uint8_t buf
[32];
876 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
879 debug("failed to open file <%s> for udf check\n", args
[0]);
883 for (i
= 16; i
< 32; i
++)
885 grub_file_seek(file
, i
* 2048);
886 grub_file_read(file
, buf
, sizeof(buf
));
894 grub_file_seek(file
, i
* 2048);
895 grub_file_read(file
, buf
, sizeof(buf
));
897 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
900 grub_file_seek(file
, i
* 2048);
901 grub_file_read(file
, buf
, sizeof(buf
));
903 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
904 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
910 grub_file_close(file
);
912 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
917 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
919 long value_long1
= 0;
920 long value_long2
= 0;
922 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
924 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
927 value_long1
= grub_strtol(args
[0], NULL
, 10);
928 value_long2
= grub_strtol(args
[2], NULL
, 10);
930 if (0 == grub_strcmp(args
[1], "eq"))
932 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
934 else if (0 == grub_strcmp(args
[1], "ne"))
936 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
938 else if (0 == grub_strcmp(args
[1], "gt"))
940 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
942 else if (0 == grub_strcmp(args
[1], "lt"))
944 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
946 else if (0 == grub_strcmp(args
[1], "ge"))
948 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
950 else if (0 == grub_strcmp(args
[1], "le"))
952 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
956 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
962 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
969 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
972 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
973 pos
= grub_strstr(buf
, ",");
979 grub_env_set(args
[1], buf
);
981 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
984 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
990 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
996 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
999 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
1001 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
1002 if (0 == grub_script_execute_sourcecode(buf
))
1004 debug("file %s exist, ventoy_compatible YES\n", buf
);
1005 grub_env_set("ventoy_compatible", "YES");
1006 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1010 debug("file %s NOT exist\n", buf
);
1014 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
1015 pos
= grub_strstr(buf
, ")");
1021 disk
= grub_disk_open(buf
);
1024 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1025 grub_disk_close(disk
);
1027 g_img_swap_tmp_buf
[703] = 0;
1028 for (i
= 318; i
< 703; i
++)
1030 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1031 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1033 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1034 grub_env_set("ventoy_compatible", "YES");
1035 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1041 debug("failed to open disk <%s>\n", buf
);
1044 grub_env_set("ventoy_compatible", "NO");
1045 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1048 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1054 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1056 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1059 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1064 if (0 == g_sort_case_sensitive
)
1066 if (grub_islower(c1
))
1068 c1
= c1
- 'a' + 'A';
1071 if (grub_islower(c2
))
1073 c2
= c2
- 'a' + 'A';
1086 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1092 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1094 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1097 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1102 if (0 == g_sort_case_sensitive
)
1104 if (grub_islower(c1
))
1106 c1
= c1
- 'a' + 'A';
1109 if (grub_islower(c2
))
1111 c2
= c2
- 'a' + 'A';
1124 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1126 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1128 grub_memcpy(img1
, img2
, sizeof(img_info
));
1129 img1
->next
= g_img_swap_tmp
.next
;
1130 img1
->prev
= g_img_swap_tmp
.prev
;
1132 g_img_swap_tmp
.next
= img2
->next
;
1133 g_img_swap_tmp
.prev
= img2
->prev
;
1134 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1137 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1141 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1149 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1153 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1163 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1172 img_iterator_node
*tmp
;
1173 img_iterator_node
*new_node
;
1174 img_iterator_node
*node
= (img_iterator_node
*)data
;
1176 len
= grub_strlen(filename
);
1180 if ((len
== 1 && filename
[0] == '.') ||
1181 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1186 if (!ventoy_img_name_valid(filename
, len
))
1191 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1196 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1198 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1199 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1202 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1207 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1210 new_node
->plugin_list_index
= index
;
1211 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1213 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1216 debug("Directory %s ignored...\n", new_node
->dir
);
1217 grub_free(new_node
);
1221 new_node
->tail
= node
->tail
;
1223 new_node
->parent
= node
;
1224 if (!node
->firstchild
)
1226 node
->firstchild
= new_node
;
1229 if (g_img_iterator_tail
)
1231 g_img_iterator_tail
->next
= new_node
;
1232 g_img_iterator_tail
= new_node
;
1236 g_img_iterator_head
.next
= new_node
;
1237 g_img_iterator_tail
= new_node
;
1243 debug("Find a file %s\n", filename
);
1249 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1251 type
= img_type_iso
;
1253 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1255 type
= img_type_wim
;
1257 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1258 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1260 type
= img_type_vhd
;
1262 #ifdef GRUB_MACHINE_EFI
1263 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1265 type
= img_type_efi
;
1268 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1270 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1272 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1273 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1278 type
= img_type_img
;
1280 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1282 type
= img_type_vtoy
;
1289 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1294 if (g_plugin_image_list
)
1296 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1297 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1298 if (VENTOY_IMG_WHITE_LIST
== g_plugin_image_list
&& index
== 0)
1300 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1303 else if (VENTOY_IMG_BLACK_LIST
== g_plugin_image_list
&& index
> 0)
1305 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf
);
1310 img
= grub_zalloc(sizeof(img_info
));
1314 img
->plugin_list_index
= index
;
1315 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1317 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1319 img
->size
= info
->size
;
1322 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1325 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1327 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1332 if (g_ventoy_img_list
)
1334 tail
= *(node
->tail
);
1340 g_ventoy_img_list
= img
;
1343 img
->id
= g_ventoy_img_count
;
1345 if (node
&& NULL
== node
->firstiso
)
1347 node
->firstiso
= img
;
1358 *((img_info
**)(node
->tail
)) = img
;
1359 g_ventoy_img_count
++;
1361 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1362 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1365 img
->class = g_menu_class
[type
];
1367 img
->menu_prefix
= g_menu_prefix
[type
];
1369 if (img_type_iso
== type
)
1371 if (ventoy_plugin_check_memdisk(img
->path
))
1373 img
->menu_prefix
= "miso";
1377 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1384 static int ventoy_arch_mode_init(void)
1386 #ifdef GRUB_MACHINE_EFI
1387 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1389 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1390 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1392 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1394 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1395 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1399 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1400 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1403 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1404 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1410 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1412 int len
= GRUB_UINT_MAX
;
1413 const char *value
= NULL
;
1414 char name
[32] = {0};
1415 char plat
[32] = {0};
1416 char guidstr
[32] = {0};
1417 ventoy_guid guid
= VENTOY_GUID
;
1418 const char *fmt1
= NULL
;
1419 const char *fmt2
= NULL
;
1420 const char *fmt3
= NULL
;
1421 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1422 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1423 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1424 const char fmtcode
[]={
1425 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1426 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1427 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1428 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1429 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1430 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1433 grub_memset(name
, 0, sizeof(name
));
1434 puint
[0] = grub_swap_bytes32(0x56454e54);
1435 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1436 puint
[2] = grub_swap_bytes32(0x45525349);
1437 puint
[1] = grub_swap_bytes32(0x4f595f56);
1438 value
= ventoy_get_env(name
);
1440 grub_memset(name
, 0, sizeof(name
));
1441 puint
[1] = grub_swap_bytes32(0x5f544f50);
1442 puint
[0] = grub_swap_bytes32(0x56544c45);
1443 fmt1
= ventoy_get_env(name
);
1449 grub_memset(name
, 0, sizeof(name
));
1450 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1451 puint
[0] = grub_swap_bytes32(0x56544c45);
1452 fmt2
= ventoy_get_env(name
);
1454 grub_memset(name
, 0, sizeof(name
));
1455 puint
[1] = grub_swap_bytes32(0x5f434c52);
1456 puint
[0] = grub_swap_bytes32(0x56544c45);
1457 fmt3
= ventoy_get_env(name
);
1459 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1461 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1463 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1464 #pragma GCC diagnostic push
1465 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1466 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1467 fmt1
? fmt1
: fmtdata
,
1468 fmt2
? fmt2
: fmtdata
+ 4,
1469 value
? value
: "", plat
, guidstr
,
1470 fmt3
? fmt3
: fmtdata
+ 6);
1471 #pragma GCC diagnostic pop
1473 grub_memset(name
, 0, sizeof(name
));
1474 puint
[0] = grub_swap_bytes32(0x76746f79);
1475 puint
[2] = grub_swap_bytes32(0x656e7365);
1476 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1477 ventoy_set_env(name
, guidstr
);
1482 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1486 grub_uint8_t md5
[16];
1490 grub_memset(input
, 0, sizeof(input
));
1492 grub_printf("Enter password: ");
1495 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1497 grub_password_get(input
, 128);
1498 if (grub_strcmp(pwd
->text
, input
) == 0)
1503 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1505 grub_password_get(input
, 128);
1506 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1507 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1512 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1514 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1515 grub_password_get(input
+ offset
, 128);
1517 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1518 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1524 grub_printf("Invalid password!\n\n");
1531 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1533 img_info
*minimg
= NULL
;
1534 img_info
*img
= (img_info
*)(node
->firstiso
);
1536 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1538 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1553 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1555 img_iterator_node
*Minchild
= NULL
;
1556 img_iterator_node
*child
= node
->firstchild
;
1558 while (child
&& child
->parent
== node
)
1560 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1564 child
= child
->next
;
1569 Minchild
->select
= 1;
1575 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1578 img_info
*img
= NULL
;
1579 const char *dir_class
= NULL
;
1580 const char *dir_alias
= NULL
;
1581 img_iterator_node
*child
= NULL
;
1583 if (node
->isocnt
== 0 || node
->done
== 1)
1588 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1590 offset
= node
->parent
->dirlen
;
1593 if (node
== &g_img_iterator_head
)
1595 if (g_default_menu_mode
== 0)
1597 if (g_tree_view_menu_style
== 0)
1599 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1600 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1601 " echo 'return ...' \n"
1606 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1607 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1615 node
->dir
[node
->dirlen
- 1] = 0;
1616 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1619 dir_class
= "vtoydir";
1622 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1625 if (g_tree_view_menu_style
== 0)
1627 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1628 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1629 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1633 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1634 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1635 dir_alias
, dir_class
, node
->dir
+ offset
);
1640 dir_alias
= node
->dir
+ offset
;
1642 if (g_tree_view_menu_style
== 0)
1644 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1645 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1646 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1650 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1651 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1652 dir_alias
, dir_class
, node
->dir
+ offset
);
1656 if (g_tree_view_menu_style
== 0)
1658 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1659 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1660 " echo 'return ...' \n"
1665 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1666 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1672 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1674 ventoy_dynamic_tree_menu(child
);
1677 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1679 if (g_tree_view_menu_style
== 0)
1681 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1682 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1685 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1686 img
->unsupport
? "[***********] " : "",
1687 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1689 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1693 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1694 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1697 img
->unsupport
? "[***********] " : "",
1698 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1700 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1704 if (node
!= &g_img_iterator_head
)
1706 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1713 int ventoy_check_device_result(int ret
)
1717 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1718 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1719 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1723 grub_printf(VTOY_WARNING
"\n");
1724 grub_printf(VTOY_WARNING
"\n");
1725 grub_printf(VTOY_WARNING
"\n\n\n");
1727 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1728 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1730 grub_printf("\n\nWill exit after 10 seconds ...... ");
1738 int ventoy_check_device(grub_device_t dev
)
1742 grub_uint64_t offset
;
1747 struct grub_partition
*partition
;
1749 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1751 return ventoy_check_device_result(1 | 0x1000);
1754 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1755 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1756 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1758 #ifndef GRUB_MACHINE_EFI
1759 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1760 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1761 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1763 return ventoy_check_device_result(2 | 0x1000);
1772 /* We must have partition 2 */
1775 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1779 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1783 return ventoy_check_device_result(3 | 0x1000);
1786 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1788 grub_file_close(file
);
1789 return ventoy_check_device_result(4 | 0x1000);
1792 partition
= dev
->disk
->partition
;
1793 if (partition
->number
!= 0 || partition
->start
!= 2048)
1795 return ventoy_check_device_result(5);
1800 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
1802 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
1803 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
1804 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
1806 grub_file_close(file
);
1807 return ventoy_check_device_result(6);
1812 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1813 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1814 PartTbl
[1].SectorCount
!= 65536)
1816 grub_file_close(file
);
1817 return ventoy_check_device_result(6);
1823 offset
= partition
->start
+ partition
->len
;
1824 partition
= file
->device
->disk
->partition
;
1825 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1827 grub_file_close(file
);
1828 return ventoy_check_device_result(7);
1832 grub_file_close(file
);
1834 if (workaround
== 0)
1836 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1837 dev2
= grub_device_open(devname
);
1840 return ventoy_check_device_result(8);
1843 fs
= grub_fs_probe(dev2
);
1846 grub_device_close(dev2
);
1847 return ventoy_check_device_result(9);
1850 fs
->fs_label(dev2
, &label
);
1851 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1853 grub_device_close(dev2
);
1854 return ventoy_check_device_result(10);
1857 grub_device_close(dev2
);
1860 return ventoy_check_device_result(0);
1863 static int ventoy_set_default_menu(void)
1869 const char *strdata
= NULL
;
1870 img_info
*cur
= NULL
;
1871 img_info
*default_node
= NULL
;
1872 const char *default_image
= NULL
;
1874 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1875 if (default_image
&& default_image
[0] == '/')
1877 img_len
= grub_strlen(default_image
);
1879 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1881 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1893 if (0 == g_default_menu_mode
)
1895 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1899 def
= grub_strdup(default_image
);
1905 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1907 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1908 if (strdata
&& strdata
[0] == '/')
1910 pos
= def
+ grub_strlen(strdata
);
1921 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1924 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1928 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1936 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1940 grub_device_t dev
= NULL
;
1941 img_info
*cur
= NULL
;
1942 img_info
*tail
= NULL
;
1943 const char *strdata
= NULL
;
1944 char *device_name
= NULL
;
1946 img_iterator_node
*node
= NULL
;
1947 img_iterator_node
*tmp
= NULL
;
1953 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1956 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1958 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1961 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1962 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1964 g_filt_dot_underscore_file
= 1;
1967 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1968 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1970 g_sort_case_sensitive
= 1;
1973 device_name
= grub_file_get_device_name(args
[0]);
1979 g_enum_dev
= dev
= grub_device_open(device_name
);
1985 g_enum_fs
= fs
= grub_fs_probe(dev
);
1991 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1993 debug("unsupported fs:<%s>\n", fs
->name
);
1994 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1998 ventoy_set_env("vtoy_iso_fs", fs
->name
);
2000 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2001 if (strdata
&& strdata
[0] == '1')
2003 g_default_menu_mode
= 1;
2006 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
2008 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
2010 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2011 if (strdata
&& strdata
[0] == '/')
2013 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
2014 if (g_img_iterator_head
.dir
[len
- 1] != '/')
2016 g_img_iterator_head
.dir
[len
++] = '/';
2018 g_img_iterator_head
.dirlen
= len
;
2022 g_img_iterator_head
.dirlen
= 1;
2023 grub_strcpy(g_img_iterator_head
.dir
, "/");
2026 g_img_iterator_head
.tail
= &tail
;
2028 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2030 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
2033 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2034 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2036 g_tree_view_menu_style
= 1;
2039 ventoy_set_default_menu();
2041 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2043 ventoy_dynamic_tree_menu(node
);
2047 node
= g_img_iterator_head
.next
;
2055 /* sort image list by image name */
2056 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2058 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2060 if (ventoy_cmp_img(cur
, tail
) > 0)
2062 ventoy_swap_img(cur
, tail
);
2067 if (g_default_menu_mode
== 1)
2069 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2070 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2071 " echo 'return ...' \n"
2075 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2077 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2078 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2081 cur
->unsupport
? "[***********] " : "",
2082 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2084 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2087 g_tree_script_buf
[g_tree_script_pos
] = 0;
2088 g_list_script_buf
[g_list_script_pos
] = 0;
2090 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2091 grub_env_set(args
[1], buf
);
2095 check_free(device_name
, grub_free
);
2096 check_free(dev
, grub_device_close
);
2098 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2102 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2104 img_info
*next
= NULL
;
2105 img_info
*cur
= g_ventoy_img_list
;
2118 g_ventoy_img_list
= NULL
;
2119 g_ventoy_img_count
= 0;
2121 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2124 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2127 img_info
*cur
= g_ventoy_img_list
;
2131 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2133 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2136 img_id
= grub_strtol(args
[0], NULL
, 10);
2137 if (img_id
>= g_ventoy_img_count
)
2139 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2142 debug("Find image %ld name \n", img_id
);
2144 while (cur
&& img_id
> 0)
2152 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2155 debug("image name is %s\n", cur
->name
);
2157 grub_env_set(args
[1], cur
->name
);
2159 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2162 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2167 const char *id
= NULL
;
2168 img_info
*cur
= g_ventoy_img_list
;
2172 if (argc
< 1 || argc
> 2)
2174 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2177 id
= grub_env_get("chosen");
2179 pos
= grub_strstr(id
, "VID_");
2182 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2186 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2191 if (img_id
== cur
->id
)
2200 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2203 grub_env_set(args
[0], cur
->path
);
2207 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2208 grub_env_set(args
[1], value
);
2211 g_svd_replace_offset
= 0;
2213 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2216 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2223 device_name
= grub_file_get_device_name(filename
);
2235 pos2
= grub_strstr(pos
, ",");
2238 pos2
= grub_strstr(pos
, ")");
2246 disk
= grub_disk_open(pos
);
2249 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2250 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2251 grub_disk_close(disk
);
2258 grub_free(device_name
);
2262 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2264 eltorito_descriptor desc
;
2266 grub_memset(&desc
, 0, sizeof(desc
));
2267 grub_file_seek(file
, 17 * 2048);
2268 grub_file_read(file
, &desc
, sizeof(desc
));
2270 if (desc
.type
!= 0 || desc
.version
!= 1)
2275 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2276 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2284 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2288 grub_uint8_t buf
[512];
2289 grub_uint8_t parttype
[] = { 0x04, 0x06, 0x0B, 0x0C };
2291 grub_file_seek(file
, sector
* 2048);
2292 grub_file_read(file
, buf
, sizeof(buf
));
2294 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2296 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2300 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2305 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2307 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2309 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2313 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2315 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2320 if (x86count
&& buf
[32] == 0x88 && buf
[33] == 0x04)
2322 for (i
= 0; i
< (int)(ARRAY_SIZE(parttype
)); i
++)
2324 if (buf
[36] == parttype
[i
])
2326 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file
->name
, buf
[36]);
2332 debug("%s does not contain efi eltorito\n", file
->name
);
2336 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2339 const char *fs
= NULL
;
2340 const char *cdprompt
= NULL
;
2342 grub_uint8_t chksum
= 0;
2345 disk
= file
->device
->disk
;
2346 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2348 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2349 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2350 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2352 pos
= grub_strstr(file
->name
, "/");
2358 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2360 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2362 param
->vtoy_img_size
= file
->size
;
2364 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2365 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2367 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2369 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2370 param
->vtoy_reserved
[4] = 0;
2371 if (g_ventoy_chain_type
== 1) /* Windows */
2373 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2374 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2376 param
->vtoy_reserved
[4] = 1;
2380 fs
= ventoy_get_env("ventoy_fs_probe");
2381 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2383 param
->vtoy_reserved
[3] = 1;
2386 /* calculate checksum */
2387 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2389 chksum
+= *((grub_uint8_t
*)param
+ i
);
2391 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2396 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2398 grub_uint32_t i
= 0;
2399 grub_uint64_t total
= 0;
2400 ventoy_img_chunk
*chunk
= NULL
;
2402 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2404 chunk
= chunklist
->chunk
+ i
;
2406 if (chunk
->disk_start_sector
<= start
)
2408 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2412 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2415 if (total
!= ((file
->size
+ 511) / 512))
2417 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2424 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2428 grub_uint32_t i
= 0;
2429 grub_uint32_t sector
= 0;
2430 grub_uint32_t count
= 0;
2431 grub_off_t size
= 0;
2432 grub_off_t read
= 0;
2434 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2435 if (fs_type
== ventoy_fs_exfat
)
2437 grub_fat_get_file_chunk(start
, file
, chunklist
);
2439 else if (fs_type
== ventoy_fs_ext
)
2441 grub_ext_get_file_chunk(start
, file
, chunklist
);
2445 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2446 file
->read_hook_data
= chunklist
;
2448 for (size
= file
->size
; size
> 0; size
-= read
)
2450 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2451 grub_file_read(file
, NULL
, read
);
2454 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2456 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2457 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2460 if (ventoy_fs_udf
== fs_type
)
2462 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2464 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2465 chunklist
->chunk
[i
].img_start_sector
= sector
;
2466 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2472 len
= (int)grub_strlen(file
->name
);
2473 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2474 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2475 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2476 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2478 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2480 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2490 chunklist
->chunk
[i
].img_start_sector
= sector
;
2491 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2499 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2503 grub_disk_addr_t start
;
2508 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2511 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2514 g_conf_replace_node
= NULL
;
2515 g_conf_replace_offset
= 0;
2517 if (g_img_chunk_list
.chunk
)
2519 grub_free(g_img_chunk_list
.chunk
);
2522 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2524 grub_file_close(file
);
2525 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2528 /* get image chunk data */
2529 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2530 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2531 if (NULL
== g_img_chunk_list
.chunk
)
2533 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2536 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2537 g_img_chunk_list
.cur_chunk
= 0;
2539 start
= file
->device
->disk
->partition
->start
;
2541 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2543 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2544 grub_file_close(file
);
2548 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2551 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2552 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2555 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2557 grub_uint64_t offset
= 0;
2558 grub_uint32_t align
= 0;
2559 grub_file_t file
= NULL
;
2560 conf_replace
*node
= NULL
;
2566 debug("select conf replace argc:%d\n", argc
);
2573 node
= ventoy_plugin_find_conf_replace(args
[1]);
2576 debug("Conf replace not found for %s\n", args
[1]);
2580 debug("Find conf replace for %s\n", args
[1]);
2582 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2585 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2589 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2590 grub_file_close(file
);
2592 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2595 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2599 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2601 if (align
> vtoy_max_replace_file_size
)
2603 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2607 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2608 g_conf_replace_new_len
= (int)file
->size
;
2609 g_conf_replace_new_len_align
= align
;
2611 g_conf_replace_node
= node
;
2612 g_conf_replace_offset
= offset
+ 2;
2614 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2619 grub_file_close(file
);
2621 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2624 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2629 char configfile
[128];
2630 install_template
*node
= NULL
;
2636 debug("select auto installation argc:%d\n", argc
);
2643 node
= ventoy_plugin_find_install_template(args
[0]);
2646 debug("Auto install template not found for %s\n", args
[0]);
2650 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2652 node
->cursel
= node
->autosel
- 1;
2653 debug("Auto install template auto select %d\n", node
->autosel
);
2657 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2663 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2664 " echo %s\n}\n", "123");
2666 for (i
= 0; i
< node
->templatenum
; i
++)
2668 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2670 node
->templatepath
[i
].path
);
2673 g_ventoy_menu_esc
= 1;
2674 g_ventoy_suppress_esc
= 1;
2676 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2677 grub_script_execute_sourcecode(configfile
);
2679 g_ventoy_menu_esc
= 0;
2680 g_ventoy_suppress_esc
= 0;
2684 node
->cursel
= g_ventoy_last_entry
- 1;
2686 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2689 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2694 char configfile
[128];
2695 persistence_config
*node
;
2701 debug("select persistence argc:%d\n", argc
);
2708 node
= ventoy_plugin_find_persistent(args
[0]);
2711 debug("Persistence image not found for %s\n", args
[0]);
2715 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2717 node
->cursel
= node
->autosel
- 1;
2718 debug("Persistence image auto select %d\n", node
->autosel
);
2722 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2728 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2729 " echo %s\n}\n", "123");
2731 for (i
= 0; i
< node
->backendnum
; i
++)
2733 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2735 node
->backendpath
[i
].path
);
2739 g_ventoy_menu_esc
= 1;
2740 g_ventoy_suppress_esc
= 1;
2742 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2743 grub_script_execute_sourcecode(configfile
);
2745 g_ventoy_menu_esc
= 0;
2746 g_ventoy_suppress_esc
= 0;
2750 node
->cursel
= g_ventoy_last_entry
- 1;
2752 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2755 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2758 ventoy_img_chunk
*cur
;
2764 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2766 cur
= g_img_chunk_list
.chunk
+ i
;
2767 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2768 cur
->img_start_sector
, cur
->img_end_sector
,
2769 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2773 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2776 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2780 ventoy_img_chunk_list chunklist
;
2785 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2788 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2791 /* get image chunk data */
2792 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2793 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2794 if (NULL
== chunklist
.chunk
)
2796 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2799 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2800 chunklist
.cur_chunk
= 0;
2802 ventoy_get_block_list(file
, &chunklist
, 0);
2804 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2806 grub_printf("########## UNSUPPORTED ###############\n");
2809 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2811 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2813 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2814 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2817 grub_printf("\n==================================\n");
2819 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2821 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2822 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2823 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2824 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2825 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2829 grub_free(chunklist
.chunk
);
2830 grub_file_close(file
);
2832 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2835 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2838 ventoy_grub_param_file_replace
*replace
= NULL
;
2846 replace
= &(g_grub_param
->file_replace
);
2847 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2849 replace
->old_name_cnt
= 0;
2850 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2852 replace
->old_name_cnt
++;
2853 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2856 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2859 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2862 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2870 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2871 grub_printf("%s", g_list_script_buf
);
2875 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2876 grub_printf("%s", g_tree_script_buf
);
2882 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2884 img_info
*cur
= g_ventoy_img_list
;
2892 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2893 grub_printf("name:<%s>\n\n", cur
->name
);
2900 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2906 ventoy_plugin_dump_injection();
2911 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2917 ventoy_plugin_dump_auto_install();
2922 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2928 ventoy_plugin_dump_persistence();
2933 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2944 if (args
[0][0] == '0')
2946 return g_ventoy_memdisk_mode
? 0 : 1;
2948 else if (args
[0][0] == '1')
2950 return g_ventoy_iso_raw
? 0 : 1;
2952 else if (args
[0][0] == '2')
2954 return g_ventoy_iso_uefi_drv
? 0 : 1;
2960 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2962 static int configfile_mode
= 0;
2963 char memfile
[128] = {0};
2970 * args[0]: 0:normal 1:configfile
2971 * args[1]: 0:list_buf 1:tree_buf
2976 debug("Invalid argc %d\n", argc
);
2980 if (args
[0][0] == '0')
2982 if (args
[1][0] == '0')
2984 grub_script_execute_sourcecode(g_list_script_buf
);
2988 grub_script_execute_sourcecode(g_tree_script_buf
);
2993 if (configfile_mode
)
2995 debug("Now already in F3 mode %d\n", configfile_mode
);
2999 if (args
[1][0] == '0')
3001 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3002 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
3006 g_ventoy_last_entry
= -1;
3007 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3008 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
3011 configfile_mode
= 1;
3012 grub_script_execute_sourcecode(memfile
);
3013 configfile_mode
= 0;
3019 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3030 g_ventoy_case_insensitive
= 1;
3031 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
3032 g_ventoy_case_insensitive
= 0;
3038 grub_file_close(file
);
3044 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3049 const char *isopath
= NULL
;
3051 ventoy_mbr_head mbr
;
3058 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3061 isopath
= grub_env_get("vtoy_iso_part");
3064 debug("isopath is null %p\n", isopath
);
3068 debug("isopath is %s\n", isopath
);
3070 for (id
= 0; id
< 30 && (find
== 0); id
++)
3072 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3073 if (grub_strstr(isopath
, hdname
))
3075 debug("skip %s ...\n", hdname
);
3079 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3081 disk
= grub_disk_open(hdname
);
3084 debug("%s not exist\n", hdname
);
3088 grub_memset(&mbr
, 0, sizeof(mbr
));
3089 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3091 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3093 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3094 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3097 grub_env_set(args
[0], hdname
);
3101 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3105 debug("read %s failed\n", hdname
);
3108 grub_disk_close(disk
);
3114 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3125 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3128 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3131 debug("failed to open file %s\n", args
[0]);
3135 buf
= grub_malloc(len
);
3142 grub_file_read(file
, buf
, len
- 1);
3144 ventoy_get_line(buf
);
3145 ventoy_set_env(args
[1], buf
);
3149 grub_check_free(buf
);
3150 grub_file_close(file
);
3155 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3160 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3161 "0 %llu linear /dev/ventoy %llu\n",
3162 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3167 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3169 char *device_name
= NULL
;
3170 grub_device_t dev
= NULL
;
3175 g_part_list_pos
= 0;
3176 grub_env_unset("vtoy_img_part_file");
3183 device_name
= grub_file_get_device_name(args
[0]);
3186 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3190 dev
= grub_device_open(device_name
);
3193 debug("grub_device_open failed, %s\n", device_name
);
3197 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3199 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3200 grub_env_set("vtoy_img_part_file", buf
);
3204 check_free(device_name
, grub_free
);
3205 check_free(dev
, grub_device_close
);
3211 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3222 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3225 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3228 debug("failed to open file %s\n", args
[0]);
3232 buf
= grub_malloc(file
->size
+ 1);
3238 buf
[file
->size
] = 0;
3239 grub_file_read(file
, buf
, file
->size
);
3241 if (grub_strstr(buf
, args
[1]))
3248 grub_check_free(buf
);
3249 grub_file_close(file
);
3254 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3260 ventoy_iso9660_vd pvd
;
3267 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid space \n", cmd_raw_name
);
3270 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3273 debug("failed to open file %s\n", args
[0]);
3277 grub_file_seek(file
, 16 * 2048);
3278 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3279 if (len
!= sizeof(pvd
))
3281 debug("failed to read pvd %d\n", len
);
3285 grub_memset(buf
, 0, sizeof(buf
));
3286 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3287 ventoy_set_env(args
[1], buf
);
3289 grub_memset(buf
, 0, sizeof(buf
));
3290 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3291 ventoy_set_env(args
[2], buf
);
3295 grub_snprintf(buf
, sizeof(buf
), "%llu", (ulonglong
)size
);
3296 ventoy_set_env(args
[3], buf
);
3299 grub_file_close(file
);
3304 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3315 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3318 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3321 debug("failed to open file %s\n", args
[0]);
3325 grub_memset(buf
, 0, sizeof(buf
));
3326 grub_file_seek(file
, 16 * 2048 + 813);
3327 len
= (int)grub_file_read(file
, buf
, 17);
3330 debug("failed to read create date %d\n", len
);
3334 ventoy_set_env(args
[1], buf
);
3337 grub_file_close(file
);
3342 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3348 ventoy_env_hook_root(1);
3353 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3359 ventoy_env_hook_root(0);
3364 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3371 int image_sector_size
;
3373 ventoy_chain_head
*chain
;
3374 ventoy_img_chunk
*chunk
;
3375 ventoy_os_param
*osparam
;
3376 ventoy_image_location
*location
;
3377 ventoy_image_disk_region
*region
;
3378 struct grub_acpi_table_header
*acpi
;
3387 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3389 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3395 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3397 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3399 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3403 img_chunk_num
= chain
->img_chunk_num
;
3405 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3406 datalen
= sizeof(ventoy_os_param
) + loclen
;
3408 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3409 acpi
= grub_zalloc(buflen
);
3415 /* Step1: Fill acpi table header */
3416 grub_memcpy(acpi
->signature
, "VTOY", 4);
3417 acpi
->length
= buflen
;
3419 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3420 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3422 acpi
->creator_id
[0] = 1;
3423 acpi
->creator_rev
= 1;
3425 /* Step2: Fill data */
3426 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3427 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3428 osparam
->vtoy_img_location_addr
= 0;
3429 osparam
->vtoy_img_location_len
= loclen
;
3430 osparam
->chksum
= 0;
3431 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3433 location
= (ventoy_image_location
*)(osparam
+ 1);
3434 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3435 location
->image_sector_size
= image_sector_size
;
3436 location
->disk_sector_size
= chain
->disk_sector_size
;
3437 location
->region_count
= img_chunk_num
;
3439 region
= location
->regions
;
3440 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3441 if (512 == image_sector_size
)
3443 for (i
= 0; i
< img_chunk_num
; i
++)
3445 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3446 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3447 region
->disk_start_sector
= chunk
->disk_start_sector
;
3454 for (i
= 0; i
< img_chunk_num
; i
++)
3456 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3457 region
->image_start_sector
= chunk
->img_start_sector
;
3458 region
->disk_start_sector
= chunk
->disk_start_sector
;
3464 /* Step3: Fill acpi checksum */
3466 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3468 /* load acpi table */
3469 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3470 grub_script_execute_sourcecode(cmd
);
3474 VENTOY_CMD_RETURN(0);
3477 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3483 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3484 g_ventoy_last_entry
= -1;
3489 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3495 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3500 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3502 grub_uint64_t sectors
;
3504 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3506 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3510 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3513 return sectors
* 512;
3516 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3518 const char *pos
= filename
+ 1;
3526 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3528 grub_strncpy((char *)data
, filename
, 128);
3539 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3542 char *device_name
= NULL
;
3543 grub_device_t dev
= NULL
;
3544 grub_fs_t fs
= NULL
;
3545 char buf
[128] = {0};
3551 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3555 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3557 device_name
= grub_file_get_device_name(args
[0]);
3560 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3564 dev
= grub_device_open(device_name
);
3567 debug("grub_device_open failed, %s\n", device_name
);
3571 fs
= grub_fs_probe(dev
);
3574 debug("grub_fs_probe failed, %s\n", device_name
);
3578 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3582 ventoy_set_env(args
[2], buf
);
3589 check_free(device_name
, grub_free
);
3590 check_free(dev
, grub_device_close
);
3595 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3605 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3606 if (!g_ventoy_part_info
)
3611 disk
= grub_disk_open(args
[0]);
3614 debug("Failed to open disk %s\n", args
[0]);
3618 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3620 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3621 grub_disk_close(disk
);
3623 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3624 dev
= grub_device_open(name
);
3627 /* make sure that we are running in a correct Ventoy device */
3628 ret
= ventoy_check_device(dev
);
3629 grub_device_close(dev
);
3640 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3643 grub_uint8_t zeroguid
[16] = {0};
3648 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3651 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3653 if (id
>= 1 && id
<= 128)
3655 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3663 if (id
>= 1 && id
<= 4)
3665 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3675 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3678 char *device_name
= NULL
;
3679 grub_device_t dev
= NULL
;
3680 grub_fs_t fs
= NULL
;
3687 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3691 device_name
= grub_file_get_device_name(args
[0]);
3694 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3698 dev
= grub_device_open(device_name
);
3701 debug("grub_device_open failed, %s\n", device_name
);
3705 fs
= grub_fs_probe(dev
);
3708 debug("grub_fs_probe failed, %s\n", device_name
);
3712 fs
->fs_label(dev
, &label
);
3715 ventoy_set_env(args
[1], label
);
3723 check_free(device_name
, grub_free
);
3724 check_free(dev
, grub_device_close
);
3729 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3733 grub_snprintf((char *)data
, 256, "%s", filename
);
3741 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3744 char *device_name
= NULL
;
3745 grub_device_t dev
= NULL
;
3746 grub_fs_t fs
= NULL
;
3747 char name
[256] ={0};
3753 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3757 device_name
= grub_file_get_device_name(args
[0]);
3760 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3764 dev
= grub_device_open(device_name
);
3767 debug("grub_device_open failed, %s\n", device_name
);
3771 fs
= grub_fs_probe(dev
);
3774 debug("grub_fs_probe failed, %s\n", device_name
);
3778 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3781 ventoy_set_env(args
[2], name
);
3788 check_free(device_name
, grub_free
);
3789 check_free(dev
, grub_device_close
);
3794 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3804 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3808 for (pos
= args
[0]; *pos
; pos
++)
3822 grub_env_set(args
[1], args
[0]);
3832 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3834 struct grub_video_mode_info info
;
3841 if (!g_video_mode_list
)
3843 ventoy_enum_video_mode();
3846 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3848 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3852 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3855 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3857 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3858 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3860 VENTOY_CMD_RETURN(0);
3863 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3865 struct grub_video_mode_info info
;
3872 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3874 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3878 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3881 grub_env_set(args
[0], buf
);
3883 VENTOY_CMD_RETURN(0);
3886 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3894 if (!g_video_mode_list
)
3899 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3900 if (id
< g_video_mode_num
)
3902 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3903 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3906 grub_env_set(args
[1], buf
);
3908 VENTOY_CMD_RETURN(0);
3911 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3913 grub_uint64_t size
= 0;
3916 char fullpath
[256] = {0};
3919 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3922 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3925 debug("grub_file_open failed <%s>\n", fullpath
);
3931 grub_file_close(file
);
3935 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3939 char fullpath
[256] = {0};
3942 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3945 file
= grub_file_open(fullpath
, type
);
3948 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3955 int ventoy_is_file_exist(const char *fmt
, ...)
3960 char buf
[256] = {0};
3962 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3966 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3969 grub_strncpy(pos
+ len
, "\" ]", 3);
3971 debug("script exec %s\n", buf
);
3973 if (0 == grub_script_execute_sourcecode(buf
))
3981 int ventoy_is_dir_exist(const char *fmt
, ...)
3986 char buf
[256] = {0};
3988 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
3992 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3995 grub_strncpy(pos
+ len
, "\" ]", 3);
3997 debug("script exec %s\n", buf
);
3999 if (0 == grub_script_execute_sourcecode(buf
))
4007 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
4010 grub_uint8_t
*outbuf
;
4011 grub_uint8_t gzHdr
[10] =
4013 0x1F, 0x8B, /* magic */
4016 0,0,0,0, /* mtime */
4021 grub_memset(&s
, 0, sizeof(mz_stream
));
4023 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
4025 outbuf
= (grub_uint8_t
*)mem_out
;
4027 mem_out_len
-= sizeof(gzHdr
) + 8;
4028 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
4029 outbuf
+= sizeof(gzHdr
);
4031 s
.avail_in
= mem_in_len
;
4034 s
.avail_out
= mem_out_len
;
4035 s
.next_out
= outbuf
;
4037 mz_deflate(&s
, MZ_FINISH
);
4041 outbuf
+= s
.total_out
;
4042 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
4043 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
4045 return s
.total_out
+ sizeof(gzHdr
) + 8;
4048 static int ventoy_env_init(void)
4052 grub_env_set("vtdebug_flag", "");
4054 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4055 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4056 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4057 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4059 ventoy_filt_register(0, ventoy_wrapper_open
);
4061 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4064 g_grub_param
->grub_env_get
= grub_env_get
;
4065 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4066 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4067 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4068 grub_env_set("env_param", buf
);
4069 grub_env_set("ventoy_env_param", buf
);
4070 grub_env_export("ventoy_env_param");
4076 static cmd_para ventoy_cmds
[] =
4078 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4079 { "vt_mod", ventoy_cmd_mod
, 0, NULL
, "{Int} {Int} {Var}", "mod integer variable", NULL
},
4080 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4081 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4082 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4083 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4084 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4085 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4086 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4087 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4088 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4089 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4090 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4091 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4092 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4093 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4094 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4095 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4096 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4097 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4098 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4100 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4101 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4102 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4103 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4104 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4105 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4106 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4108 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4109 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4110 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4111 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4112 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4113 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4114 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4115 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4118 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4119 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4120 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4121 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4122 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4123 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4124 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4125 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4126 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4127 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4128 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4130 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4131 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4132 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4133 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4134 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4135 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4137 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4138 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4139 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4140 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4141 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4142 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4143 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4144 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4145 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4146 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4148 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4149 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4150 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4151 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4152 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4153 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4154 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4155 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4157 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4158 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4159 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4162 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4163 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4164 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4166 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4167 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4168 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4171 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4172 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4173 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4174 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4175 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4176 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4177 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4178 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4179 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4180 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4182 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4183 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4184 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4190 GRUB_MOD_INIT(ventoy
)
4193 cmd_para
*cur
= NULL
;
4197 ventoy_arch_mode_init();
4199 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4201 cur
= ventoy_cmds
+ i
;
4202 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4203 cur
->summary
, cur
->description
, cur
->parser
);
4207 GRUB_MOD_FINI(ventoy
)
4211 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4213 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);