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_collect_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
;
1284 else if (len
>= 9 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vcfg"))
1286 if (filename
[len
- 9] == '.' || (len
>= 10 && filename
[len
- 10] == '.'))
1288 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1289 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf
);
1298 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1303 if (g_plugin_image_list
)
1305 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1306 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1307 if (VENTOY_IMG_WHITE_LIST
== g_plugin_image_list
&& index
== 0)
1309 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1312 else if (VENTOY_IMG_BLACK_LIST
== g_plugin_image_list
&& index
> 0)
1314 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf
);
1319 img
= grub_zalloc(sizeof(img_info
));
1323 img
->plugin_list_index
= index
;
1324 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1326 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1328 img
->size
= info
->size
;
1331 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1334 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1336 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1341 if (g_ventoy_img_list
)
1343 tail
= *(node
->tail
);
1349 g_ventoy_img_list
= img
;
1352 img
->id
= g_ventoy_img_count
;
1354 if (node
&& NULL
== node
->firstiso
)
1356 node
->firstiso
= img
;
1367 *((img_info
**)(node
->tail
)) = img
;
1368 g_ventoy_img_count
++;
1370 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1371 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1374 img
->class = g_menu_class
[type
];
1376 img
->menu_prefix
= g_menu_prefix
[type
];
1378 if (img_type_iso
== type
)
1380 if (ventoy_plugin_check_memdisk(img
->path
))
1382 img
->menu_prefix
= "miso";
1386 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1393 static int ventoy_arch_mode_init(void)
1395 #ifdef GRUB_MACHINE_EFI
1396 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1398 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1399 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1401 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1403 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1404 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1408 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1409 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1412 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1413 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1419 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1421 int len
= GRUB_UINT_MAX
;
1422 const char *value
= NULL
;
1423 char name
[32] = {0};
1424 char plat
[32] = {0};
1425 char guidstr
[32] = {0};
1426 ventoy_guid guid
= VENTOY_GUID
;
1427 const char *fmt1
= NULL
;
1428 const char *fmt2
= NULL
;
1429 const char *fmt3
= NULL
;
1430 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1431 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1432 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1433 const char fmtcode
[]={
1434 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1435 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1436 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1437 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1438 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1439 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1442 grub_memset(name
, 0, sizeof(name
));
1443 puint
[0] = grub_swap_bytes32(0x56454e54);
1444 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1445 puint
[2] = grub_swap_bytes32(0x45525349);
1446 puint
[1] = grub_swap_bytes32(0x4f595f56);
1447 value
= ventoy_get_env(name
);
1449 grub_memset(name
, 0, sizeof(name
));
1450 puint
[1] = grub_swap_bytes32(0x5f544f50);
1451 puint
[0] = grub_swap_bytes32(0x56544c45);
1452 fmt1
= ventoy_get_env(name
);
1458 grub_memset(name
, 0, sizeof(name
));
1459 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1460 puint
[0] = grub_swap_bytes32(0x56544c45);
1461 fmt2
= ventoy_get_env(name
);
1463 grub_memset(name
, 0, sizeof(name
));
1464 puint
[1] = grub_swap_bytes32(0x5f434c52);
1465 puint
[0] = grub_swap_bytes32(0x56544c45);
1466 fmt3
= ventoy_get_env(name
);
1468 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1470 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1472 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1473 #pragma GCC diagnostic push
1474 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1475 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1476 fmt1
? fmt1
: fmtdata
,
1477 fmt2
? fmt2
: fmtdata
+ 4,
1478 value
? value
: "", plat
, guidstr
,
1479 fmt3
? fmt3
: fmtdata
+ 6);
1480 #pragma GCC diagnostic pop
1482 grub_memset(name
, 0, sizeof(name
));
1483 puint
[0] = grub_swap_bytes32(0x76746f79);
1484 puint
[2] = grub_swap_bytes32(0x656e7365);
1485 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1486 ventoy_set_env(name
, guidstr
);
1491 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1495 grub_uint8_t md5
[16];
1499 grub_memset(input
, 0, sizeof(input
));
1501 grub_printf("Enter password: ");
1504 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1506 grub_password_get(input
, 128);
1507 if (grub_strcmp(pwd
->text
, input
) == 0)
1512 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1514 grub_password_get(input
, 128);
1515 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1516 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1521 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1523 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1524 grub_password_get(input
+ offset
, 128);
1526 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1527 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1533 grub_printf("Invalid password!\n\n");
1540 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1542 img_info
*minimg
= NULL
;
1543 img_info
*img
= (img_info
*)(node
->firstiso
);
1545 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1547 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1562 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1564 img_iterator_node
*Minchild
= NULL
;
1565 img_iterator_node
*child
= node
->firstchild
;
1567 while (child
&& child
->parent
== node
)
1569 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1573 child
= child
->next
;
1578 Minchild
->select
= 1;
1584 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1587 img_info
*img
= NULL
;
1588 const char *dir_class
= NULL
;
1589 const char *dir_alias
= NULL
;
1590 img_iterator_node
*child
= NULL
;
1592 if (node
->isocnt
== 0 || node
->done
== 1)
1597 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1599 offset
= node
->parent
->dirlen
;
1602 if (node
== &g_img_iterator_head
)
1604 if (g_default_menu_mode
== 0)
1606 if (g_tree_view_menu_style
== 0)
1608 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1609 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1610 " echo 'return ...' \n"
1615 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1616 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1624 node
->dir
[node
->dirlen
- 1] = 0;
1625 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1628 dir_class
= "vtoydir";
1631 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1634 if (g_tree_view_menu_style
== 0)
1636 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1637 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1638 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1642 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1643 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1644 dir_alias
, dir_class
, node
->dir
+ offset
);
1649 dir_alias
= node
->dir
+ offset
;
1651 if (g_tree_view_menu_style
== 0)
1653 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1654 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1655 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1659 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1660 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1661 dir_alias
, dir_class
, node
->dir
+ offset
);
1665 if (g_tree_view_menu_style
== 0)
1667 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1668 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1669 " echo 'return ...' \n"
1674 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1675 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1681 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1683 ventoy_dynamic_tree_menu(child
);
1686 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1688 if (g_tree_view_menu_style
== 0)
1690 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1691 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1694 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1695 img
->unsupport
? "[***********] " : "",
1696 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1698 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1702 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1703 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1706 img
->unsupport
? "[***********] " : "",
1707 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1709 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1713 if (node
!= &g_img_iterator_head
)
1715 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1722 int ventoy_check_device_result(int ret
)
1726 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1727 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1728 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1732 grub_printf(VTOY_WARNING
"\n");
1733 grub_printf(VTOY_WARNING
"\n");
1734 grub_printf(VTOY_WARNING
"\n\n\n");
1736 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1737 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1739 grub_printf("\n\nWill exit after 10 seconds ...... ");
1747 int ventoy_check_device(grub_device_t dev
)
1751 grub_uint64_t offset
;
1756 struct grub_partition
*partition
;
1758 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1760 return ventoy_check_device_result(1 | 0x1000);
1763 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1764 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1765 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1767 #ifndef GRUB_MACHINE_EFI
1768 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1769 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1770 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1772 return ventoy_check_device_result(2 | 0x1000);
1781 /* We must have partition 2 */
1784 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1788 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1792 return ventoy_check_device_result(3 | 0x1000);
1795 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1797 grub_file_close(file
);
1798 return ventoy_check_device_result(4 | 0x1000);
1801 partition
= dev
->disk
->partition
;
1802 if (partition
->number
!= 0 || partition
->start
!= 2048)
1804 return ventoy_check_device_result(5);
1809 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
1811 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
1812 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
1813 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
1815 grub_file_close(file
);
1816 return ventoy_check_device_result(6);
1821 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1822 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1823 PartTbl
[1].SectorCount
!= 65536)
1825 grub_file_close(file
);
1826 return ventoy_check_device_result(6);
1832 offset
= partition
->start
+ partition
->len
;
1833 partition
= file
->device
->disk
->partition
;
1834 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1836 grub_file_close(file
);
1837 return ventoy_check_device_result(7);
1841 grub_file_close(file
);
1843 if (workaround
== 0)
1845 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1846 dev2
= grub_device_open(devname
);
1849 return ventoy_check_device_result(8);
1852 fs
= grub_fs_probe(dev2
);
1855 grub_device_close(dev2
);
1856 return ventoy_check_device_result(9);
1859 fs
->fs_label(dev2
, &label
);
1860 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1862 grub_device_close(dev2
);
1863 return ventoy_check_device_result(10);
1866 grub_device_close(dev2
);
1869 return ventoy_check_device_result(0);
1872 static int ventoy_set_default_menu(void)
1878 const char *strdata
= NULL
;
1879 img_info
*cur
= NULL
;
1880 img_info
*default_node
= NULL
;
1881 const char *default_image
= NULL
;
1883 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1884 if (default_image
&& default_image
[0] == '/')
1886 img_len
= grub_strlen(default_image
);
1888 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1890 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1902 if (0 == g_default_menu_mode
)
1904 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1908 def
= grub_strdup(default_image
);
1914 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1916 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1917 if (strdata
&& strdata
[0] == '/')
1919 pos
= def
+ grub_strlen(strdata
);
1930 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1933 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1937 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1945 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1949 grub_device_t dev
= NULL
;
1950 img_info
*cur
= NULL
;
1951 img_info
*tail
= NULL
;
1952 const char *strdata
= NULL
;
1953 char *device_name
= NULL
;
1955 img_iterator_node
*node
= NULL
;
1956 img_iterator_node
*tmp
= NULL
;
1962 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1965 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1967 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1970 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1971 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1973 g_filt_dot_underscore_file
= 1;
1976 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1977 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1979 g_sort_case_sensitive
= 1;
1982 device_name
= grub_file_get_device_name(args
[0]);
1988 g_enum_dev
= dev
= grub_device_open(device_name
);
1994 g_enum_fs
= fs
= grub_fs_probe(dev
);
2000 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
2002 debug("unsupported fs:<%s>\n", fs
->name
);
2003 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2007 ventoy_set_env("vtoy_iso_fs", fs
->name
);
2009 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2010 if (strdata
&& strdata
[0] == '1')
2012 g_default_menu_mode
= 1;
2015 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
2017 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
2019 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2020 if (strdata
&& strdata
[0] == '/')
2022 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
2023 if (g_img_iterator_head
.dir
[len
- 1] != '/')
2025 g_img_iterator_head
.dir
[len
++] = '/';
2027 g_img_iterator_head
.dirlen
= len
;
2031 g_img_iterator_head
.dirlen
= 1;
2032 grub_strcpy(g_img_iterator_head
.dir
, "/");
2035 g_img_iterator_head
.tail
= &tail
;
2037 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2039 fs
->fs_dir(dev
, node
->dir
, ventoy_collect_img_files
, node
);
2042 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2043 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2045 g_tree_view_menu_style
= 1;
2048 ventoy_set_default_menu();
2050 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2052 ventoy_dynamic_tree_menu(node
);
2056 node
= g_img_iterator_head
.next
;
2064 /* sort image list by image name */
2065 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2067 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2069 if (ventoy_cmp_img(cur
, tail
) > 0)
2071 ventoy_swap_img(cur
, tail
);
2076 if (g_default_menu_mode
== 1)
2078 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2079 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2080 " echo 'return ...' \n"
2084 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2086 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2087 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2090 cur
->unsupport
? "[***********] " : "",
2091 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2093 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2096 g_tree_script_buf
[g_tree_script_pos
] = 0;
2097 g_list_script_buf
[g_list_script_pos
] = 0;
2099 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2100 grub_env_set(args
[1], buf
);
2104 check_free(device_name
, grub_free
);
2105 check_free(dev
, grub_device_close
);
2107 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2111 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2113 img_info
*next
= NULL
;
2114 img_info
*cur
= g_ventoy_img_list
;
2127 g_ventoy_img_list
= NULL
;
2128 g_ventoy_img_count
= 0;
2130 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2133 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2136 img_info
*cur
= g_ventoy_img_list
;
2140 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2142 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2145 img_id
= grub_strtol(args
[0], NULL
, 10);
2146 if (img_id
>= g_ventoy_img_count
)
2148 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2151 debug("Find image %ld name \n", img_id
);
2153 while (cur
&& img_id
> 0)
2161 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2164 debug("image name is %s\n", cur
->name
);
2166 grub_env_set(args
[1], cur
->name
);
2168 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2171 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2176 const char *id
= NULL
;
2177 img_info
*cur
= g_ventoy_img_list
;
2181 if (argc
< 1 || argc
> 2)
2183 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2186 id
= grub_env_get("chosen");
2188 pos
= grub_strstr(id
, "VID_");
2191 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2195 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2200 if (img_id
== cur
->id
)
2209 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2212 grub_env_set(args
[0], cur
->path
);
2216 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2217 grub_env_set(args
[1], value
);
2220 g_svd_replace_offset
= 0;
2222 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2225 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2232 device_name
= grub_file_get_device_name(filename
);
2244 pos2
= grub_strstr(pos
, ",");
2247 pos2
= grub_strstr(pos
, ")");
2255 disk
= grub_disk_open(pos
);
2258 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2259 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2260 grub_disk_close(disk
);
2267 grub_free(device_name
);
2271 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2273 eltorito_descriptor desc
;
2275 grub_memset(&desc
, 0, sizeof(desc
));
2276 grub_file_seek(file
, 17 * 2048);
2277 grub_file_read(file
, &desc
, sizeof(desc
));
2279 if (desc
.type
!= 0 || desc
.version
!= 1)
2284 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2285 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2293 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2297 grub_uint8_t buf
[512];
2298 grub_uint8_t parttype
[] = { 0x04, 0x06, 0x0B, 0x0C };
2300 grub_file_seek(file
, sector
* 2048);
2301 grub_file_read(file
, buf
, sizeof(buf
));
2303 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2305 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2309 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2314 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2316 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2318 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2322 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2324 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2329 if (x86count
&& buf
[32] == 0x88 && buf
[33] == 0x04)
2331 for (i
= 0; i
< (int)(ARRAY_SIZE(parttype
)); i
++)
2333 if (buf
[36] == parttype
[i
])
2335 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file
->name
, buf
[36]);
2341 debug("%s does not contain efi eltorito\n", file
->name
);
2345 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2348 const char *fs
= NULL
;
2349 const char *cdprompt
= NULL
;
2351 grub_uint8_t chksum
= 0;
2354 disk
= file
->device
->disk
;
2355 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2357 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2358 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2359 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2361 pos
= grub_strstr(file
->name
, "/");
2367 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2369 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2371 param
->vtoy_img_size
= file
->size
;
2373 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2374 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2376 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2378 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2379 param
->vtoy_reserved
[4] = 0;
2380 if (g_ventoy_chain_type
== 1) /* Windows */
2382 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2383 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2385 param
->vtoy_reserved
[4] = 1;
2389 fs
= ventoy_get_env("ventoy_fs_probe");
2390 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2392 param
->vtoy_reserved
[3] = 1;
2395 /* calculate checksum */
2396 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2398 chksum
+= *((grub_uint8_t
*)param
+ i
);
2400 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2405 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2407 grub_uint32_t i
= 0;
2408 grub_uint64_t total
= 0;
2409 ventoy_img_chunk
*chunk
= NULL
;
2411 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2413 chunk
= chunklist
->chunk
+ i
;
2415 if (chunk
->disk_start_sector
<= start
)
2417 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2421 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2424 if (total
!= ((file
->size
+ 511) / 512))
2426 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2433 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2437 grub_uint32_t i
= 0;
2438 grub_uint32_t sector
= 0;
2439 grub_uint32_t count
= 0;
2440 grub_off_t size
= 0;
2441 grub_off_t read
= 0;
2443 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2444 if (fs_type
== ventoy_fs_exfat
)
2446 grub_fat_get_file_chunk(start
, file
, chunklist
);
2448 else if (fs_type
== ventoy_fs_ext
)
2450 grub_ext_get_file_chunk(start
, file
, chunklist
);
2454 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2455 file
->read_hook_data
= chunklist
;
2457 for (size
= file
->size
; size
> 0; size
-= read
)
2459 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2460 grub_file_read(file
, NULL
, read
);
2463 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2465 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2466 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2469 if (ventoy_fs_udf
== fs_type
)
2471 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2473 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2474 chunklist
->chunk
[i
].img_start_sector
= sector
;
2475 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2481 len
= (int)grub_strlen(file
->name
);
2482 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2483 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2484 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2485 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2487 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2489 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2499 chunklist
->chunk
[i
].img_start_sector
= sector
;
2500 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2508 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2512 grub_disk_addr_t start
;
2517 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2520 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2523 g_conf_replace_node
= NULL
;
2524 g_conf_replace_offset
= 0;
2526 if (g_img_chunk_list
.chunk
)
2528 grub_free(g_img_chunk_list
.chunk
);
2531 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2533 grub_file_close(file
);
2534 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2537 /* get image chunk data */
2538 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2539 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2540 if (NULL
== g_img_chunk_list
.chunk
)
2542 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2545 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2546 g_img_chunk_list
.cur_chunk
= 0;
2548 start
= file
->device
->disk
->partition
->start
;
2550 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2552 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2553 grub_file_close(file
);
2557 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2560 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2561 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2564 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2566 grub_uint64_t offset
= 0;
2567 grub_uint32_t align
= 0;
2568 grub_file_t file
= NULL
;
2569 conf_replace
*node
= NULL
;
2575 debug("select conf replace argc:%d\n", argc
);
2582 node
= ventoy_plugin_find_conf_replace(args
[1]);
2585 debug("Conf replace not found for %s\n", args
[1]);
2589 debug("Find conf replace for %s\n", args
[1]);
2591 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2594 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2598 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2599 grub_file_close(file
);
2601 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2604 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2608 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2610 if (align
> vtoy_max_replace_file_size
)
2612 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2616 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2617 g_conf_replace_new_len
= (int)file
->size
;
2618 g_conf_replace_new_len_align
= align
;
2620 g_conf_replace_node
= node
;
2621 g_conf_replace_offset
= offset
+ 2;
2623 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2628 grub_file_close(file
);
2630 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2633 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2638 char configfile
[128];
2639 install_template
*node
= NULL
;
2645 debug("select auto installation argc:%d\n", argc
);
2652 node
= ventoy_plugin_find_install_template(args
[0]);
2655 debug("Auto install template not found for %s\n", args
[0]);
2659 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2661 node
->cursel
= node
->autosel
- 1;
2662 debug("Auto install template auto select %d\n", node
->autosel
);
2666 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2672 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2673 " echo %s\n}\n", "123");
2675 for (i
= 0; i
< node
->templatenum
; i
++)
2677 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2679 node
->templatepath
[i
].path
);
2682 g_ventoy_menu_esc
= 1;
2683 g_ventoy_suppress_esc
= 1;
2685 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2686 grub_script_execute_sourcecode(configfile
);
2688 g_ventoy_menu_esc
= 0;
2689 g_ventoy_suppress_esc
= 0;
2693 node
->cursel
= g_ventoy_last_entry
- 1;
2695 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2698 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2703 char configfile
[128];
2704 persistence_config
*node
;
2710 debug("select persistence argc:%d\n", argc
);
2717 node
= ventoy_plugin_find_persistent(args
[0]);
2720 debug("Persistence image not found for %s\n", args
[0]);
2724 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2726 node
->cursel
= node
->autosel
- 1;
2727 debug("Persistence image auto select %d\n", node
->autosel
);
2731 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2737 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2738 " echo %s\n}\n", "123");
2740 for (i
= 0; i
< node
->backendnum
; i
++)
2742 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2744 node
->backendpath
[i
].path
);
2748 g_ventoy_menu_esc
= 1;
2749 g_ventoy_suppress_esc
= 1;
2751 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2752 grub_script_execute_sourcecode(configfile
);
2754 g_ventoy_menu_esc
= 0;
2755 g_ventoy_suppress_esc
= 0;
2759 node
->cursel
= g_ventoy_last_entry
- 1;
2761 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2764 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2767 ventoy_img_chunk
*cur
;
2773 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2775 cur
= g_img_chunk_list
.chunk
+ i
;
2776 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2777 cur
->img_start_sector
, cur
->img_end_sector
,
2778 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2782 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2785 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2789 ventoy_img_chunk_list chunklist
;
2794 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2797 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2800 /* get image chunk data */
2801 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2802 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2803 if (NULL
== chunklist
.chunk
)
2805 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2808 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2809 chunklist
.cur_chunk
= 0;
2811 ventoy_get_block_list(file
, &chunklist
, 0);
2813 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2815 grub_printf("########## UNSUPPORTED ###############\n");
2818 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2820 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2822 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2823 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2826 grub_printf("\n==================================\n");
2828 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2830 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2831 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2832 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2833 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2834 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2838 grub_free(chunklist
.chunk
);
2839 grub_file_close(file
);
2841 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2844 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2847 ventoy_grub_param_file_replace
*replace
= NULL
;
2855 replace
= &(g_grub_param
->file_replace
);
2856 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2858 replace
->old_name_cnt
= 0;
2859 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2861 replace
->old_name_cnt
++;
2862 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2865 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2868 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2871 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2879 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2880 grub_printf("%s", g_list_script_buf
);
2884 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2885 grub_printf("%s", g_tree_script_buf
);
2891 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2893 img_info
*cur
= g_ventoy_img_list
;
2901 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2902 grub_printf("name:<%s>\n\n", cur
->name
);
2909 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2915 ventoy_plugin_dump_injection();
2920 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2926 ventoy_plugin_dump_auto_install();
2931 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2937 ventoy_plugin_dump_persistence();
2942 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2953 if (args
[0][0] == '0')
2955 return g_ventoy_memdisk_mode
? 0 : 1;
2957 else if (args
[0][0] == '1')
2959 return g_ventoy_iso_raw
? 0 : 1;
2961 else if (args
[0][0] == '2')
2963 return g_ventoy_iso_uefi_drv
? 0 : 1;
2969 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2971 static int configfile_mode
= 0;
2972 char memfile
[128] = {0};
2979 * args[0]: 0:normal 1:configfile
2980 * args[1]: 0:list_buf 1:tree_buf
2985 debug("Invalid argc %d\n", argc
);
2989 if (args
[0][0] == '0')
2991 if (args
[1][0] == '0')
2993 grub_script_execute_sourcecode(g_list_script_buf
);
2997 grub_script_execute_sourcecode(g_tree_script_buf
);
3002 if (configfile_mode
)
3004 debug("Now already in F3 mode %d\n", configfile_mode
);
3008 if (args
[1][0] == '0')
3010 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3011 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
3015 g_ventoy_last_entry
= -1;
3016 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3017 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
3020 configfile_mode
= 1;
3021 grub_script_execute_sourcecode(memfile
);
3022 configfile_mode
= 0;
3028 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3039 g_ventoy_case_insensitive
= 1;
3040 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
3041 g_ventoy_case_insensitive
= 0;
3047 grub_file_close(file
);
3053 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3058 const char *isopath
= NULL
;
3060 ventoy_mbr_head mbr
;
3067 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3070 isopath
= grub_env_get("vtoy_iso_part");
3073 debug("isopath is null %p\n", isopath
);
3077 debug("isopath is %s\n", isopath
);
3079 for (id
= 0; id
< 30 && (find
== 0); id
++)
3081 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3082 if (grub_strstr(isopath
, hdname
))
3084 debug("skip %s ...\n", hdname
);
3088 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3090 disk
= grub_disk_open(hdname
);
3093 debug("%s not exist\n", hdname
);
3097 grub_memset(&mbr
, 0, sizeof(mbr
));
3098 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3100 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3102 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3103 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3106 grub_env_set(args
[0], hdname
);
3110 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3114 debug("read %s failed\n", hdname
);
3117 grub_disk_close(disk
);
3123 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3134 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3137 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3140 debug("failed to open file %s\n", args
[0]);
3144 buf
= grub_malloc(len
);
3151 grub_file_read(file
, buf
, len
- 1);
3153 ventoy_get_line(buf
);
3154 ventoy_set_env(args
[1], buf
);
3158 grub_check_free(buf
);
3159 grub_file_close(file
);
3164 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3169 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3170 "0 %llu linear /dev/ventoy %llu\n",
3171 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3176 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3178 char *device_name
= NULL
;
3179 grub_device_t dev
= NULL
;
3184 g_part_list_pos
= 0;
3185 grub_env_unset("vtoy_img_part_file");
3192 device_name
= grub_file_get_device_name(args
[0]);
3195 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3199 dev
= grub_device_open(device_name
);
3202 debug("grub_device_open failed, %s\n", device_name
);
3206 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3208 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3209 grub_env_set("vtoy_img_part_file", buf
);
3213 check_free(device_name
, grub_free
);
3214 check_free(dev
, grub_device_close
);
3220 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3231 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3234 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3237 debug("failed to open file %s\n", args
[0]);
3241 buf
= grub_malloc(file
->size
+ 1);
3247 buf
[file
->size
] = 0;
3248 grub_file_read(file
, buf
, file
->size
);
3250 if (grub_strstr(buf
, args
[1]))
3257 grub_check_free(buf
);
3258 grub_file_close(file
);
3263 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3269 ventoy_iso9660_vd pvd
;
3276 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid space \n", cmd_raw_name
);
3279 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3282 debug("failed to open file %s\n", args
[0]);
3286 grub_file_seek(file
, 16 * 2048);
3287 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3288 if (len
!= sizeof(pvd
))
3290 debug("failed to read pvd %d\n", len
);
3294 grub_memset(buf
, 0, sizeof(buf
));
3295 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3296 ventoy_set_env(args
[1], buf
);
3298 grub_memset(buf
, 0, sizeof(buf
));
3299 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3300 ventoy_set_env(args
[2], buf
);
3304 grub_snprintf(buf
, sizeof(buf
), "%llu", (ulonglong
)size
);
3305 ventoy_set_env(args
[3], buf
);
3308 grub_file_close(file
);
3313 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3324 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3327 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3330 debug("failed to open file %s\n", args
[0]);
3334 grub_memset(buf
, 0, sizeof(buf
));
3335 grub_file_seek(file
, 16 * 2048 + 813);
3336 len
= (int)grub_file_read(file
, buf
, 17);
3339 debug("failed to read create date %d\n", len
);
3343 ventoy_set_env(args
[1], buf
);
3346 grub_file_close(file
);
3351 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3357 ventoy_env_hook_root(1);
3362 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3368 ventoy_env_hook_root(0);
3373 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3380 int image_sector_size
;
3382 ventoy_chain_head
*chain
;
3383 ventoy_img_chunk
*chunk
;
3384 ventoy_os_param
*osparam
;
3385 ventoy_image_location
*location
;
3386 ventoy_image_disk_region
*region
;
3387 struct grub_acpi_table_header
*acpi
;
3396 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3398 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3404 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3406 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3408 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3412 img_chunk_num
= chain
->img_chunk_num
;
3414 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3415 datalen
= sizeof(ventoy_os_param
) + loclen
;
3417 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3418 acpi
= grub_zalloc(buflen
);
3424 /* Step1: Fill acpi table header */
3425 grub_memcpy(acpi
->signature
, "VTOY", 4);
3426 acpi
->length
= buflen
;
3428 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3429 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3431 acpi
->creator_id
[0] = 1;
3432 acpi
->creator_rev
= 1;
3434 /* Step2: Fill data */
3435 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3436 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3437 osparam
->vtoy_img_location_addr
= 0;
3438 osparam
->vtoy_img_location_len
= loclen
;
3439 osparam
->chksum
= 0;
3440 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3442 location
= (ventoy_image_location
*)(osparam
+ 1);
3443 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3444 location
->image_sector_size
= image_sector_size
;
3445 location
->disk_sector_size
= chain
->disk_sector_size
;
3446 location
->region_count
= img_chunk_num
;
3448 region
= location
->regions
;
3449 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3450 if (512 == image_sector_size
)
3452 for (i
= 0; i
< img_chunk_num
; i
++)
3454 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3455 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3456 region
->disk_start_sector
= chunk
->disk_start_sector
;
3463 for (i
= 0; i
< img_chunk_num
; i
++)
3465 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3466 region
->image_start_sector
= chunk
->img_start_sector
;
3467 region
->disk_start_sector
= chunk
->disk_start_sector
;
3473 /* Step3: Fill acpi checksum */
3475 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3477 /* load acpi table */
3478 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3479 grub_script_execute_sourcecode(cmd
);
3483 VENTOY_CMD_RETURN(0);
3486 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3492 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3493 g_ventoy_last_entry
= -1;
3498 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3504 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3509 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3511 grub_uint64_t sectors
;
3513 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3515 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3519 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3522 return sectors
* 512;
3525 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3527 const char *pos
= filename
+ 1;
3535 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3537 grub_strncpy((char *)data
, filename
, 128);
3548 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3551 char *device_name
= NULL
;
3552 grub_device_t dev
= NULL
;
3553 grub_fs_t fs
= NULL
;
3554 char buf
[128] = {0};
3560 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3564 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3566 device_name
= grub_file_get_device_name(args
[0]);
3569 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3573 dev
= grub_device_open(device_name
);
3576 debug("grub_device_open failed, %s\n", device_name
);
3580 fs
= grub_fs_probe(dev
);
3583 debug("grub_fs_probe failed, %s\n", device_name
);
3587 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3591 ventoy_set_env(args
[2], buf
);
3598 check_free(device_name
, grub_free
);
3599 check_free(dev
, grub_device_close
);
3604 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3614 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3615 if (!g_ventoy_part_info
)
3620 disk
= grub_disk_open(args
[0]);
3623 debug("Failed to open disk %s\n", args
[0]);
3627 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3629 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3630 grub_disk_close(disk
);
3632 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3633 dev
= grub_device_open(name
);
3636 /* make sure that we are running in a correct Ventoy device */
3637 ret
= ventoy_check_device(dev
);
3638 grub_device_close(dev
);
3649 static grub_err_t
ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3652 const char *vcfg
= NULL
;
3657 vcfg
= ventoy_plugin_get_custom_boot(args
[0]);
3660 debug("custom boot <%s>:<%s>\n", args
[0], vcfg
);
3661 grub_env_set(args
[1], vcfg
);
3666 debug("custom boot <%s>:<NOT FOUND>\n", args
[0]);
3674 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3677 grub_uint8_t zeroguid
[16] = {0};
3682 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3685 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3687 if (id
>= 1 && id
<= 128)
3689 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3697 if (id
>= 1 && id
<= 4)
3699 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3709 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3712 char *device_name
= NULL
;
3713 grub_device_t dev
= NULL
;
3714 grub_fs_t fs
= NULL
;
3721 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3725 device_name
= grub_file_get_device_name(args
[0]);
3728 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3732 dev
= grub_device_open(device_name
);
3735 debug("grub_device_open failed, %s\n", device_name
);
3739 fs
= grub_fs_probe(dev
);
3742 debug("grub_fs_probe failed, %s\n", device_name
);
3746 fs
->fs_label(dev
, &label
);
3749 ventoy_set_env(args
[1], label
);
3757 check_free(device_name
, grub_free
);
3758 check_free(dev
, grub_device_close
);
3763 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3767 grub_snprintf((char *)data
, 256, "%s", filename
);
3775 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3778 char *device_name
= NULL
;
3779 grub_device_t dev
= NULL
;
3780 grub_fs_t fs
= NULL
;
3781 char name
[256] ={0};
3787 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3791 device_name
= grub_file_get_device_name(args
[0]);
3794 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3798 dev
= grub_device_open(device_name
);
3801 debug("grub_device_open failed, %s\n", device_name
);
3805 fs
= grub_fs_probe(dev
);
3808 debug("grub_fs_probe failed, %s\n", device_name
);
3812 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3815 ventoy_set_env(args
[2], name
);
3822 check_free(device_name
, grub_free
);
3823 check_free(dev
, grub_device_close
);
3828 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3838 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3842 for (pos
= args
[0]; *pos
; pos
++)
3856 grub_env_set(args
[1], args
[0]);
3866 static grub_err_t
ventoy_cmd_basefile(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3876 debug("ventoy_cmd_basefile, invalid param num %d\n", argc
);
3881 len
= (int)grub_strlen(buf
);
3882 for (i
= len
; i
> 0; i
--)
3884 if (buf
[i
- 1] == '/')
3886 grub_env_set(args
[1], buf
+ i
);
3891 grub_env_set(args
[1], buf
);
3896 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3898 struct grub_video_mode_info info
;
3905 if (!g_video_mode_list
)
3907 ventoy_enum_video_mode();
3910 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3912 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3916 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3919 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3921 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3922 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3924 VENTOY_CMD_RETURN(0);
3927 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3929 struct grub_video_mode_info info
;
3936 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3938 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3942 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3945 grub_env_set(args
[0], buf
);
3947 VENTOY_CMD_RETURN(0);
3950 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3958 if (!g_video_mode_list
)
3963 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3964 if (id
< g_video_mode_num
)
3966 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3967 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3970 grub_env_set(args
[1], buf
);
3972 VENTOY_CMD_RETURN(0);
3975 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3977 grub_uint64_t size
= 0;
3980 char fullpath
[256] = {0};
3983 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3986 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3989 debug("grub_file_open failed <%s>\n", fullpath
);
3995 grub_file_close(file
);
3999 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
4003 char fullpath
[256] = {0};
4006 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
4009 file
= grub_file_open(fullpath
, type
);
4012 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
4019 int ventoy_is_file_exist(const char *fmt
, ...)
4024 char buf
[256] = {0};
4026 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
4030 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
4033 grub_strncpy(pos
+ len
, "\" ]", 3);
4035 debug("script exec %s\n", buf
);
4037 if (0 == grub_script_execute_sourcecode(buf
))
4045 int ventoy_is_dir_exist(const char *fmt
, ...)
4050 char buf
[256] = {0};
4052 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
4056 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
4059 grub_strncpy(pos
+ len
, "\" ]", 3);
4061 debug("script exec %s\n", buf
);
4063 if (0 == grub_script_execute_sourcecode(buf
))
4071 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
4074 grub_uint8_t
*outbuf
;
4075 grub_uint8_t gzHdr
[10] =
4077 0x1F, 0x8B, /* magic */
4080 0,0,0,0, /* mtime */
4085 grub_memset(&s
, 0, sizeof(mz_stream
));
4087 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
4089 outbuf
= (grub_uint8_t
*)mem_out
;
4091 mem_out_len
-= sizeof(gzHdr
) + 8;
4092 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
4093 outbuf
+= sizeof(gzHdr
);
4095 s
.avail_in
= mem_in_len
;
4098 s
.avail_out
= mem_out_len
;
4099 s
.next_out
= outbuf
;
4101 mz_deflate(&s
, MZ_FINISH
);
4105 outbuf
+= s
.total_out
;
4106 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
4107 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
4109 return s
.total_out
+ sizeof(gzHdr
) + 8;
4112 static int ventoy_env_init(void)
4116 grub_env_set("vtdebug_flag", "");
4118 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4119 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4120 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4121 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4123 ventoy_filt_register(0, ventoy_wrapper_open
);
4125 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4128 g_grub_param
->grub_env_get
= grub_env_get
;
4129 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4130 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4131 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4132 grub_env_set("env_param", buf
);
4133 grub_env_set("ventoy_env_param", buf
);
4134 grub_env_export("ventoy_env_param");
4140 static cmd_para ventoy_cmds
[] =
4142 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4143 { "vt_mod", ventoy_cmd_mod
, 0, NULL
, "{Int} {Int} {Var}", "mod integer variable", NULL
},
4144 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4145 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4146 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4147 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4148 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4149 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4150 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4151 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4152 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4153 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4154 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4155 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4156 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4157 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4158 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4159 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4160 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4161 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4162 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4163 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot
, 0, NULL
, "", "", NULL
},
4164 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot
, 0, NULL
, "", "", NULL
},
4166 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4167 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4168 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4169 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4170 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4171 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4172 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4174 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4175 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4176 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4177 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4178 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4179 { "vt_file_basefile", ventoy_cmd_basefile
, 0, NULL
, "", "", NULL
},
4180 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4181 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4182 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4185 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4186 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4187 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4188 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4189 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4190 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4191 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4192 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4193 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4194 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4195 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4197 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4198 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4199 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4200 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4201 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4202 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4204 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4205 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4206 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4207 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4208 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4209 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4210 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4211 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4212 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4213 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4215 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4216 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4217 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4218 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4219 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4220 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4221 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4222 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4224 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4225 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4226 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4229 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4230 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4231 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4233 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4234 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4235 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4238 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4239 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4240 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4241 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4242 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4243 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4244 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4245 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4246 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4247 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4249 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4250 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4251 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4257 GRUB_MOD_INIT(ventoy
)
4260 cmd_para
*cur
= NULL
;
4264 ventoy_arch_mode_init();
4266 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4268 cur
= ventoy_cmds
+ i
;
4269 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4270 cur
->summary
, cur
->description
, cur
->parser
);
4274 GRUB_MOD_FINI(ventoy
)
4278 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4280 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);