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_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
552 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
555 debug("failed to open file <%s> for udf check\n", args
[0]);
559 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
561 grub_env_set(args
[1], buf
);
563 grub_file_close(file
);
569 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
577 g_wimboot_enable
= 0;
578 grub_check_free(g_wimiso_path
);
579 grub_check_free(g_wimiso_chunk_list
.chunk
);
581 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
587 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
588 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
589 if (NULL
== g_wimiso_chunk_list
.chunk
)
591 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
594 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
595 g_wimiso_chunk_list
.cur_chunk
= 0;
597 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
599 g_wimboot_enable
= 1;
600 g_wimiso_path
= grub_strdup(args
[0]);
602 grub_file_close(file
);
607 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
613 grub_uint32_t offset
;
615 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
618 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
622 len
= (int)file
->size
;
624 data
= (char *)grub_malloc(file
->size
);
630 grub_file_read(file
, data
, file
->size
);
631 grub_file_close(file
);
633 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
634 grub_script_execute_sourcecode(exec
);
636 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
637 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
638 grub_file_close(file
);
640 grub_script_execute_sourcecode("loopback -d efiboot");
644 *direntoff
= offset
+ 2;
649 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
659 ventoy_iso9660_override
*dirent
;
668 totlen
= sizeof(ventoy_chain_head
);
670 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
672 debug("failed to load efiboot template %d\n", len
);
678 debug("efiboot template len:%d offset:%d\n", len
, offset
);
680 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
683 debug("failed to open file <%s>\n", args
[0]);
687 totlen
+= ventoy_align_2k(file
->size
);
689 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
690 dirent
->first_sector
= len
/ 2048;
691 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
692 dirent
->size
= (grub_uint32_t
)file
->size
;
693 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
695 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
697 #ifdef GRUB_MACHINE_EFI
698 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
700 data
= (char *)grub_malloc(totlen
);
703 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
705 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
706 grub_check_free(buf
);
708 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
709 grub_file_close(file
);
711 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
712 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
713 grub_env_set(name
, value
);
715 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
716 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
717 grub_env_set(name
, value
);
722 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
739 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
742 debug("failed to open file <%s>\n", args
[0]);
746 #ifdef GRUB_MACHINE_EFI
747 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
749 buf
= (char *)grub_malloc(file
->size
);
752 grub_file_read(file
, buf
, file
->size
);
754 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
755 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
756 grub_env_set(name
, value
);
758 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
759 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
760 grub_env_set(name
, value
);
762 grub_file_close(file
);
768 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
786 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
789 debug("failed to open file <%s> for udf check\n", args
[0]);
793 headlen
= sizeof(ventoy_chain_head
);
795 #ifdef GRUB_MACHINE_EFI
796 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
798 buf
= (char *)grub_malloc(headlen
+ file
->size
);
801 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
803 grub_file_read(file
, buf
+ headlen
, file
->size
);
805 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
806 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
807 grub_env_set(name
, value
);
809 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
810 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
811 grub_env_set(name
, value
);
813 grub_file_close(file
);
819 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
828 if (args
[0][0] == '1')
830 grub_iso9660_set_nojoliet(1);
834 grub_iso9660_set_nojoliet(0);
840 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
845 grub_uint8_t buf
[32];
856 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
859 debug("failed to open file <%s> for udf check\n", args
[0]);
863 for (i
= 16; i
< 32; i
++)
865 grub_file_seek(file
, i
* 2048);
866 grub_file_read(file
, buf
, sizeof(buf
));
874 grub_file_seek(file
, i
* 2048);
875 grub_file_read(file
, buf
, sizeof(buf
));
877 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
880 grub_file_seek(file
, i
* 2048);
881 grub_file_read(file
, buf
, sizeof(buf
));
883 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
884 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
890 grub_file_close(file
);
892 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
897 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
899 long value_long1
= 0;
900 long value_long2
= 0;
902 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
904 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
907 value_long1
= grub_strtol(args
[0], NULL
, 10);
908 value_long2
= grub_strtol(args
[2], NULL
, 10);
910 if (0 == grub_strcmp(args
[1], "eq"))
912 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
914 else if (0 == grub_strcmp(args
[1], "ne"))
916 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
918 else if (0 == grub_strcmp(args
[1], "gt"))
920 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
922 else if (0 == grub_strcmp(args
[1], "lt"))
924 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
926 else if (0 == grub_strcmp(args
[1], "ge"))
928 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
930 else if (0 == grub_strcmp(args
[1], "le"))
932 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
936 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
942 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
949 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
952 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
953 pos
= grub_strstr(buf
, ",");
959 grub_env_set(args
[1], buf
);
961 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
964 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
970 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
976 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
979 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
981 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
982 if (0 == grub_script_execute_sourcecode(buf
))
984 debug("file %s exist, ventoy_compatible YES\n", buf
);
985 grub_env_set("ventoy_compatible", "YES");
986 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
990 debug("file %s NOT exist\n", buf
);
994 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
995 pos
= grub_strstr(buf
, ")");
1001 disk
= grub_disk_open(buf
);
1004 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1005 grub_disk_close(disk
);
1007 g_img_swap_tmp_buf
[703] = 0;
1008 for (i
= 318; i
< 703; i
++)
1010 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1011 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1013 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1014 grub_env_set("ventoy_compatible", "YES");
1015 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1021 debug("failed to open disk <%s>\n", buf
);
1024 grub_env_set("ventoy_compatible", "NO");
1025 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1028 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1034 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1036 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1039 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1044 if (0 == g_sort_case_sensitive
)
1046 if (grub_islower(c1
))
1048 c1
= c1
- 'a' + 'A';
1051 if (grub_islower(c2
))
1053 c2
= c2
- 'a' + 'A';
1066 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1072 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1074 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1077 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1082 if (0 == g_sort_case_sensitive
)
1084 if (grub_islower(c1
))
1086 c1
= c1
- 'a' + 'A';
1089 if (grub_islower(c2
))
1091 c2
= c2
- 'a' + 'A';
1104 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1106 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1108 grub_memcpy(img1
, img2
, sizeof(img_info
));
1109 img1
->next
= g_img_swap_tmp
.next
;
1110 img1
->prev
= g_img_swap_tmp
.prev
;
1112 g_img_swap_tmp
.next
= img2
->next
;
1113 g_img_swap_tmp
.prev
= img2
->prev
;
1114 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1117 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1121 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1129 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1133 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1143 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1152 img_iterator_node
*tmp
;
1153 img_iterator_node
*new_node
;
1154 img_iterator_node
*node
= (img_iterator_node
*)data
;
1156 len
= grub_strlen(filename
);
1160 if ((len
== 1 && filename
[0] == '.') ||
1161 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1166 if (!ventoy_img_name_valid(filename
, len
))
1171 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1176 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1178 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1179 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1182 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1187 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1190 new_node
->plugin_list_index
= index
;
1191 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1193 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1196 debug("Directory %s ignored...\n", new_node
->dir
);
1197 grub_free(new_node
);
1201 new_node
->tail
= node
->tail
;
1203 new_node
->parent
= node
;
1204 if (!node
->firstchild
)
1206 node
->firstchild
= new_node
;
1209 if (g_img_iterator_tail
)
1211 g_img_iterator_tail
->next
= new_node
;
1212 g_img_iterator_tail
= new_node
;
1216 g_img_iterator_head
.next
= new_node
;
1217 g_img_iterator_tail
= new_node
;
1223 debug("Find a file %s\n", filename
);
1229 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1231 type
= img_type_iso
;
1233 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1235 type
= img_type_wim
;
1237 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1238 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1240 type
= img_type_vhd
;
1242 #ifdef GRUB_MACHINE_EFI
1243 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1245 type
= img_type_efi
;
1248 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1250 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1252 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1253 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1258 type
= img_type_img
;
1260 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1262 type
= img_type_vtoy
;
1269 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1274 if (g_plugin_image_list
)
1276 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1277 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1278 if (VENTOY_IMG_WHITE_LIST
== g_plugin_image_list
&& index
== 0)
1280 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1283 else if (VENTOY_IMG_BLACK_LIST
== g_plugin_image_list
&& index
> 0)
1285 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf
);
1290 img
= grub_zalloc(sizeof(img_info
));
1294 img
->plugin_list_index
= index
;
1295 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1297 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1299 img
->size
= info
->size
;
1302 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1305 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1307 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1312 if (g_ventoy_img_list
)
1314 tail
= *(node
->tail
);
1320 g_ventoy_img_list
= img
;
1323 img
->id
= g_ventoy_img_count
;
1325 if (node
&& NULL
== node
->firstiso
)
1327 node
->firstiso
= img
;
1338 *((img_info
**)(node
->tail
)) = img
;
1339 g_ventoy_img_count
++;
1341 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1342 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1345 img
->class = g_menu_class
[type
];
1347 img
->menu_prefix
= g_menu_prefix
[type
];
1349 if (img_type_iso
== type
)
1351 if (ventoy_plugin_check_memdisk(img
->path
))
1353 img
->menu_prefix
= "miso";
1357 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1364 static int ventoy_arch_mode_init(void)
1366 #ifdef GRUB_MACHINE_EFI
1367 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1369 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1370 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1372 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1374 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1375 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1379 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1380 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1383 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1384 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1390 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1392 int len
= GRUB_UINT_MAX
;
1393 const char *value
= NULL
;
1394 char name
[32] = {0};
1395 char plat
[32] = {0};
1396 char guidstr
[32] = {0};
1397 ventoy_guid guid
= VENTOY_GUID
;
1398 const char *fmt1
= NULL
;
1399 const char *fmt2
= NULL
;
1400 const char *fmt3
= NULL
;
1401 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1402 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1403 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1404 const char fmtcode
[]={
1405 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1406 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1407 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1408 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1409 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1410 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1413 grub_memset(name
, 0, sizeof(name
));
1414 puint
[0] = grub_swap_bytes32(0x56454e54);
1415 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1416 puint
[2] = grub_swap_bytes32(0x45525349);
1417 puint
[1] = grub_swap_bytes32(0x4f595f56);
1418 value
= ventoy_get_env(name
);
1420 grub_memset(name
, 0, sizeof(name
));
1421 puint
[1] = grub_swap_bytes32(0x5f544f50);
1422 puint
[0] = grub_swap_bytes32(0x56544c45);
1423 fmt1
= ventoy_get_env(name
);
1429 grub_memset(name
, 0, sizeof(name
));
1430 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1431 puint
[0] = grub_swap_bytes32(0x56544c45);
1432 fmt2
= ventoy_get_env(name
);
1434 grub_memset(name
, 0, sizeof(name
));
1435 puint
[1] = grub_swap_bytes32(0x5f434c52);
1436 puint
[0] = grub_swap_bytes32(0x56544c45);
1437 fmt3
= ventoy_get_env(name
);
1439 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1441 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1443 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1444 #pragma GCC diagnostic push
1445 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1446 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1447 fmt1
? fmt1
: fmtdata
,
1448 fmt2
? fmt2
: fmtdata
+ 4,
1449 value
? value
: "", plat
, guidstr
,
1450 fmt3
? fmt3
: fmtdata
+ 6);
1451 #pragma GCC diagnostic pop
1453 grub_memset(name
, 0, sizeof(name
));
1454 puint
[0] = grub_swap_bytes32(0x76746f79);
1455 puint
[2] = grub_swap_bytes32(0x656e7365);
1456 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1457 ventoy_set_env(name
, guidstr
);
1462 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1466 grub_uint8_t md5
[16];
1470 grub_memset(input
, 0, sizeof(input
));
1472 grub_printf("Enter password: ");
1475 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1477 grub_password_get(input
, 128);
1478 if (grub_strcmp(pwd
->text
, input
) == 0)
1483 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1485 grub_password_get(input
, 128);
1486 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1487 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1492 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1494 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1495 grub_password_get(input
+ offset
, 128);
1497 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1498 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1504 grub_printf("Invalid password!\n\n");
1511 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1513 img_info
*minimg
= NULL
;
1514 img_info
*img
= (img_info
*)(node
->firstiso
);
1516 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1518 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1533 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1535 img_iterator_node
*Minchild
= NULL
;
1536 img_iterator_node
*child
= node
->firstchild
;
1538 while (child
&& child
->parent
== node
)
1540 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1544 child
= child
->next
;
1549 Minchild
->select
= 1;
1555 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1558 img_info
*img
= NULL
;
1559 const char *dir_class
= NULL
;
1560 const char *dir_alias
= NULL
;
1561 img_iterator_node
*child
= NULL
;
1563 if (node
->isocnt
== 0 || node
->done
== 1)
1568 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1570 offset
= node
->parent
->dirlen
;
1573 if (node
== &g_img_iterator_head
)
1575 if (g_default_menu_mode
== 0)
1577 if (g_tree_view_menu_style
== 0)
1579 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1580 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1581 " echo 'return ...' \n"
1586 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1587 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1595 node
->dir
[node
->dirlen
- 1] = 0;
1596 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1599 dir_class
= "vtoydir";
1602 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1605 if (g_tree_view_menu_style
== 0)
1607 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1608 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1609 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1613 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1614 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1615 dir_alias
, dir_class
, node
->dir
+ offset
);
1620 dir_alias
= node
->dir
+ offset
;
1622 if (g_tree_view_menu_style
== 0)
1624 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1625 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1626 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1630 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1631 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1632 dir_alias
, dir_class
, node
->dir
+ offset
);
1636 if (g_tree_view_menu_style
== 0)
1638 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1639 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1640 " echo 'return ...' \n"
1645 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1646 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1652 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1654 ventoy_dynamic_tree_menu(child
);
1657 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1659 if (g_tree_view_menu_style
== 0)
1661 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1662 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1665 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1666 img
->unsupport
? "[***********] " : "",
1667 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1669 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1673 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1674 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1677 img
->unsupport
? "[***********] " : "",
1678 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1680 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1684 if (node
!= &g_img_iterator_head
)
1686 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1693 int ventoy_check_device_result(int ret
)
1697 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1698 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1699 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1703 grub_printf(VTOY_WARNING
"\n");
1704 grub_printf(VTOY_WARNING
"\n");
1705 grub_printf(VTOY_WARNING
"\n\n\n");
1707 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1708 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1710 grub_printf("\n\nWill exit after 10 seconds ...... ");
1718 int ventoy_check_device(grub_device_t dev
)
1722 grub_uint64_t offset
;
1727 struct grub_partition
*partition
;
1729 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1731 return ventoy_check_device_result(1 | 0x1000);
1734 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1735 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1736 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1738 #ifndef GRUB_MACHINE_EFI
1739 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1740 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1741 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1743 return ventoy_check_device_result(2 | 0x1000);
1752 /* We must have partition 2 */
1755 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1759 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1763 return ventoy_check_device_result(3 | 0x1000);
1766 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1768 grub_file_close(file
);
1769 return ventoy_check_device_result(4 | 0x1000);
1772 partition
= dev
->disk
->partition
;
1773 if (partition
->number
!= 0 || partition
->start
!= 2048)
1775 return ventoy_check_device_result(5);
1780 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
1782 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
1783 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
1784 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
1786 grub_file_close(file
);
1787 return ventoy_check_device_result(6);
1792 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1793 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1794 PartTbl
[1].SectorCount
!= 65536)
1796 grub_file_close(file
);
1797 return ventoy_check_device_result(6);
1803 offset
= partition
->start
+ partition
->len
;
1804 partition
= file
->device
->disk
->partition
;
1805 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1807 grub_file_close(file
);
1808 return ventoy_check_device_result(7);
1812 grub_file_close(file
);
1814 if (workaround
== 0)
1816 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1817 dev2
= grub_device_open(devname
);
1820 return ventoy_check_device_result(8);
1823 fs
= grub_fs_probe(dev2
);
1826 grub_device_close(dev2
);
1827 return ventoy_check_device_result(9);
1830 fs
->fs_label(dev2
, &label
);
1831 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1833 grub_device_close(dev2
);
1834 return ventoy_check_device_result(10);
1837 grub_device_close(dev2
);
1840 return ventoy_check_device_result(0);
1843 static int ventoy_set_default_menu(void)
1849 const char *strdata
= NULL
;
1850 img_info
*cur
= NULL
;
1851 img_info
*default_node
= NULL
;
1852 const char *default_image
= NULL
;
1854 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1855 if (default_image
&& default_image
[0] == '/')
1857 img_len
= grub_strlen(default_image
);
1859 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1861 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1873 if (0 == g_default_menu_mode
)
1875 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1879 def
= grub_strdup(default_image
);
1885 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1887 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1888 if (strdata
&& strdata
[0] == '/')
1890 pos
= def
+ grub_strlen(strdata
);
1901 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1904 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1908 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1916 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1920 grub_device_t dev
= NULL
;
1921 img_info
*cur
= NULL
;
1922 img_info
*tail
= NULL
;
1923 const char *strdata
= NULL
;
1924 char *device_name
= NULL
;
1926 img_iterator_node
*node
= NULL
;
1927 img_iterator_node
*tmp
= NULL
;
1933 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1936 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1938 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1941 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1942 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1944 g_filt_dot_underscore_file
= 1;
1947 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1948 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1950 g_sort_case_sensitive
= 1;
1953 device_name
= grub_file_get_device_name(args
[0]);
1959 g_enum_dev
= dev
= grub_device_open(device_name
);
1965 g_enum_fs
= fs
= grub_fs_probe(dev
);
1971 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1973 debug("unsupported fs:<%s>\n", fs
->name
);
1974 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1978 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1980 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1981 if (strdata
&& strdata
[0] == '1')
1983 g_default_menu_mode
= 1;
1986 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1988 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1990 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1991 if (strdata
&& strdata
[0] == '/')
1993 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1994 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1996 g_img_iterator_head
.dir
[len
++] = '/';
1998 g_img_iterator_head
.dirlen
= len
;
2002 g_img_iterator_head
.dirlen
= 1;
2003 grub_strcpy(g_img_iterator_head
.dir
, "/");
2006 g_img_iterator_head
.tail
= &tail
;
2008 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2010 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
2013 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2014 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2016 g_tree_view_menu_style
= 1;
2019 ventoy_set_default_menu();
2021 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2023 ventoy_dynamic_tree_menu(node
);
2027 node
= g_img_iterator_head
.next
;
2035 /* sort image list by image name */
2036 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2038 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2040 if (ventoy_cmp_img(cur
, tail
) > 0)
2042 ventoy_swap_img(cur
, tail
);
2047 if (g_default_menu_mode
== 1)
2049 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2050 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2051 " echo 'return ...' \n"
2055 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2057 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2058 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2061 cur
->unsupport
? "[***********] " : "",
2062 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2064 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2067 g_tree_script_buf
[g_tree_script_pos
] = 0;
2068 g_list_script_buf
[g_list_script_pos
] = 0;
2070 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2071 grub_env_set(args
[1], buf
);
2075 check_free(device_name
, grub_free
);
2076 check_free(dev
, grub_device_close
);
2078 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2082 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2084 img_info
*next
= NULL
;
2085 img_info
*cur
= g_ventoy_img_list
;
2098 g_ventoy_img_list
= NULL
;
2099 g_ventoy_img_count
= 0;
2101 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2104 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2107 img_info
*cur
= g_ventoy_img_list
;
2111 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2113 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2116 img_id
= grub_strtol(args
[0], NULL
, 10);
2117 if (img_id
>= g_ventoy_img_count
)
2119 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2122 debug("Find image %ld name \n", img_id
);
2124 while (cur
&& img_id
> 0)
2132 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2135 debug("image name is %s\n", cur
->name
);
2137 grub_env_set(args
[1], cur
->name
);
2139 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2142 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2147 const char *id
= NULL
;
2148 img_info
*cur
= g_ventoy_img_list
;
2152 if (argc
< 1 || argc
> 2)
2154 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2157 id
= grub_env_get("chosen");
2159 pos
= grub_strstr(id
, "VID_");
2162 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2166 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2171 if (img_id
== cur
->id
)
2180 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2183 grub_env_set(args
[0], cur
->path
);
2187 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2188 grub_env_set(args
[1], value
);
2191 g_svd_replace_offset
= 0;
2193 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2196 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2203 device_name
= grub_file_get_device_name(filename
);
2215 pos2
= grub_strstr(pos
, ",");
2218 pos2
= grub_strstr(pos
, ")");
2226 disk
= grub_disk_open(pos
);
2229 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2230 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2231 grub_disk_close(disk
);
2238 grub_free(device_name
);
2242 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2244 eltorito_descriptor desc
;
2246 grub_memset(&desc
, 0, sizeof(desc
));
2247 grub_file_seek(file
, 17 * 2048);
2248 grub_file_read(file
, &desc
, sizeof(desc
));
2250 if (desc
.type
!= 0 || desc
.version
!= 1)
2255 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2256 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2264 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2268 grub_uint8_t buf
[512];
2269 grub_uint8_t parttype
[] = { 0x04, 0x06, 0x0B, 0x0C };
2271 grub_file_seek(file
, sector
* 2048);
2272 grub_file_read(file
, buf
, sizeof(buf
));
2274 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2276 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2280 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2285 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2287 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2289 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2293 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2295 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2300 if (x86count
&& buf
[32] == 0x88 && buf
[33] == 0x04)
2302 for (i
= 0; i
< (int)(ARRAY_SIZE(parttype
)); i
++)
2304 if (buf
[36] == parttype
[i
])
2306 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file
->name
, buf
[36]);
2312 debug("%s does not contain efi eltorito\n", file
->name
);
2316 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2319 const char *fs
= NULL
;
2320 const char *cdprompt
= NULL
;
2322 grub_uint8_t chksum
= 0;
2325 disk
= file
->device
->disk
;
2326 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2328 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2329 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2330 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2332 pos
= grub_strstr(file
->name
, "/");
2338 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2340 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2342 param
->vtoy_img_size
= file
->size
;
2344 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2345 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2347 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2349 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2350 param
->vtoy_reserved
[4] = 0;
2351 if (g_ventoy_chain_type
== 1) /* Windows */
2353 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2354 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2356 param
->vtoy_reserved
[4] = 1;
2360 fs
= ventoy_get_env("ventoy_fs_probe");
2361 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2363 param
->vtoy_reserved
[3] = 1;
2366 /* calculate checksum */
2367 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2369 chksum
+= *((grub_uint8_t
*)param
+ i
);
2371 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2376 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2378 grub_uint32_t i
= 0;
2379 grub_uint64_t total
= 0;
2380 ventoy_img_chunk
*chunk
= NULL
;
2382 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2384 chunk
= chunklist
->chunk
+ i
;
2386 if (chunk
->disk_start_sector
<= start
)
2388 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2392 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2395 if (total
!= ((file
->size
+ 511) / 512))
2397 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2404 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2408 grub_uint32_t i
= 0;
2409 grub_uint32_t sector
= 0;
2410 grub_uint32_t count
= 0;
2411 grub_off_t size
= 0;
2412 grub_off_t read
= 0;
2414 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2415 if (fs_type
== ventoy_fs_exfat
)
2417 grub_fat_get_file_chunk(start
, file
, chunklist
);
2419 else if (fs_type
== ventoy_fs_ext
)
2421 grub_ext_get_file_chunk(start
, file
, chunklist
);
2425 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2426 file
->read_hook_data
= chunklist
;
2428 for (size
= file
->size
; size
> 0; size
-= read
)
2430 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2431 grub_file_read(file
, NULL
, read
);
2434 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2436 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2437 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2440 if (ventoy_fs_udf
== fs_type
)
2442 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2444 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2445 chunklist
->chunk
[i
].img_start_sector
= sector
;
2446 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2452 len
= (int)grub_strlen(file
->name
);
2453 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2454 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2455 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2456 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2458 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2460 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2470 chunklist
->chunk
[i
].img_start_sector
= sector
;
2471 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2479 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2483 grub_disk_addr_t start
;
2488 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2491 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2494 g_conf_replace_node
= NULL
;
2495 g_conf_replace_offset
= 0;
2497 if (g_img_chunk_list
.chunk
)
2499 grub_free(g_img_chunk_list
.chunk
);
2502 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2504 grub_file_close(file
);
2505 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2508 /* get image chunk data */
2509 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2510 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2511 if (NULL
== g_img_chunk_list
.chunk
)
2513 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2516 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2517 g_img_chunk_list
.cur_chunk
= 0;
2519 start
= file
->device
->disk
->partition
->start
;
2521 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2523 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2524 grub_file_close(file
);
2528 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2531 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2532 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2535 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2537 grub_uint64_t offset
= 0;
2538 grub_uint32_t align
= 0;
2539 grub_file_t file
= NULL
;
2540 conf_replace
*node
= NULL
;
2546 debug("select conf replace argc:%d\n", argc
);
2553 node
= ventoy_plugin_find_conf_replace(args
[1]);
2556 debug("Conf replace not found for %s\n", args
[1]);
2560 debug("Find conf replace for %s\n", args
[1]);
2562 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2565 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2569 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2570 grub_file_close(file
);
2572 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2575 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2579 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2581 if (align
> vtoy_max_replace_file_size
)
2583 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2587 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2588 g_conf_replace_new_len
= (int)file
->size
;
2589 g_conf_replace_new_len_align
= align
;
2591 g_conf_replace_node
= node
;
2592 g_conf_replace_offset
= offset
+ 2;
2594 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2599 grub_file_close(file
);
2601 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2604 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2609 char configfile
[128];
2610 install_template
*node
= NULL
;
2616 debug("select auto installation argc:%d\n", argc
);
2623 node
= ventoy_plugin_find_install_template(args
[0]);
2626 debug("Auto install template not found for %s\n", args
[0]);
2630 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2632 node
->cursel
= node
->autosel
- 1;
2633 debug("Auto install template auto select %d\n", node
->autosel
);
2637 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2643 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2644 " echo %s\n}\n", "123");
2646 for (i
= 0; i
< node
->templatenum
; i
++)
2648 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2650 node
->templatepath
[i
].path
);
2653 g_ventoy_menu_esc
= 1;
2654 g_ventoy_suppress_esc
= 1;
2656 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2657 grub_script_execute_sourcecode(configfile
);
2659 g_ventoy_menu_esc
= 0;
2660 g_ventoy_suppress_esc
= 0;
2664 node
->cursel
= g_ventoy_last_entry
- 1;
2666 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2669 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2674 char configfile
[128];
2675 persistence_config
*node
;
2681 debug("select persistence argc:%d\n", argc
);
2688 node
= ventoy_plugin_find_persistent(args
[0]);
2691 debug("Persistence image not found for %s\n", args
[0]);
2695 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2697 node
->cursel
= node
->autosel
- 1;
2698 debug("Persistence image auto select %d\n", node
->autosel
);
2702 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2708 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2709 " echo %s\n}\n", "123");
2711 for (i
= 0; i
< node
->backendnum
; i
++)
2713 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2715 node
->backendpath
[i
].path
);
2719 g_ventoy_menu_esc
= 1;
2720 g_ventoy_suppress_esc
= 1;
2722 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2723 grub_script_execute_sourcecode(configfile
);
2725 g_ventoy_menu_esc
= 0;
2726 g_ventoy_suppress_esc
= 0;
2730 node
->cursel
= g_ventoy_last_entry
- 1;
2732 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2735 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2738 ventoy_img_chunk
*cur
;
2744 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2746 cur
= g_img_chunk_list
.chunk
+ i
;
2747 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2748 cur
->img_start_sector
, cur
->img_end_sector
,
2749 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2753 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2756 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2760 ventoy_img_chunk_list chunklist
;
2765 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2768 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2771 /* get image chunk data */
2772 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2773 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2774 if (NULL
== chunklist
.chunk
)
2776 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2779 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2780 chunklist
.cur_chunk
= 0;
2782 ventoy_get_block_list(file
, &chunklist
, 0);
2784 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2786 grub_printf("########## UNSUPPORTED ###############\n");
2789 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2791 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2793 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2794 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2797 grub_printf("\n==================================\n");
2799 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2801 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2802 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2803 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2804 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2805 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2809 grub_free(chunklist
.chunk
);
2810 grub_file_close(file
);
2812 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2815 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2818 ventoy_grub_param_file_replace
*replace
= NULL
;
2826 replace
= &(g_grub_param
->file_replace
);
2827 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2829 replace
->old_name_cnt
= 0;
2830 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2832 replace
->old_name_cnt
++;
2833 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2836 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2839 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2842 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2850 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2851 grub_printf("%s", g_list_script_buf
);
2855 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2856 grub_printf("%s", g_tree_script_buf
);
2862 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2864 img_info
*cur
= g_ventoy_img_list
;
2872 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2873 grub_printf("name:<%s>\n\n", cur
->name
);
2880 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2886 ventoy_plugin_dump_injection();
2891 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2897 ventoy_plugin_dump_auto_install();
2902 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2908 ventoy_plugin_dump_persistence();
2913 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2924 if (args
[0][0] == '0')
2926 return g_ventoy_memdisk_mode
? 0 : 1;
2928 else if (args
[0][0] == '1')
2930 return g_ventoy_iso_raw
? 0 : 1;
2932 else if (args
[0][0] == '2')
2934 return g_ventoy_iso_uefi_drv
? 0 : 1;
2940 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2942 static int configfile_mode
= 0;
2943 char memfile
[128] = {0};
2950 * args[0]: 0:normal 1:configfile
2951 * args[1]: 0:list_buf 1:tree_buf
2956 debug("Invalid argc %d\n", argc
);
2960 if (args
[0][0] == '0')
2962 if (args
[1][0] == '0')
2964 grub_script_execute_sourcecode(g_list_script_buf
);
2968 grub_script_execute_sourcecode(g_tree_script_buf
);
2973 if (configfile_mode
)
2975 debug("Now already in F3 mode %d\n", configfile_mode
);
2979 if (args
[1][0] == '0')
2981 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2982 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2986 g_ventoy_last_entry
= -1;
2987 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2988 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2991 configfile_mode
= 1;
2992 grub_script_execute_sourcecode(memfile
);
2993 configfile_mode
= 0;
2999 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3010 g_ventoy_case_insensitive
= 1;
3011 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
3012 g_ventoy_case_insensitive
= 0;
3018 grub_file_close(file
);
3024 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3029 const char *isopath
= NULL
;
3031 ventoy_mbr_head mbr
;
3038 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3041 isopath
= grub_env_get("vtoy_iso_part");
3044 debug("isopath is null %p\n", isopath
);
3048 debug("isopath is %s\n", isopath
);
3050 for (id
= 0; id
< 30 && (find
== 0); id
++)
3052 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3053 if (grub_strstr(isopath
, hdname
))
3055 debug("skip %s ...\n", hdname
);
3059 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3061 disk
= grub_disk_open(hdname
);
3064 debug("%s not exist\n", hdname
);
3068 grub_memset(&mbr
, 0, sizeof(mbr
));
3069 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3071 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3073 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3074 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3077 grub_env_set(args
[0], hdname
);
3081 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3085 debug("read %s failed\n", hdname
);
3088 grub_disk_close(disk
);
3094 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3105 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3108 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3111 debug("failed to open file %s\n", args
[0]);
3115 buf
= grub_malloc(len
);
3122 grub_file_read(file
, buf
, len
- 1);
3124 ventoy_get_line(buf
);
3125 ventoy_set_env(args
[1], buf
);
3129 grub_check_free(buf
);
3130 grub_file_close(file
);
3135 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3140 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3141 "0 %llu linear /dev/ventoy %llu\n",
3142 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3147 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3149 char *device_name
= NULL
;
3150 grub_device_t dev
= NULL
;
3155 g_part_list_pos
= 0;
3156 grub_env_unset("vtoy_img_part_file");
3163 device_name
= grub_file_get_device_name(args
[0]);
3166 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3170 dev
= grub_device_open(device_name
);
3173 debug("grub_device_open failed, %s\n", device_name
);
3177 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3179 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3180 grub_env_set("vtoy_img_part_file", buf
);
3184 check_free(device_name
, grub_free
);
3185 check_free(dev
, grub_device_close
);
3191 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3202 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3205 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3208 debug("failed to open file %s\n", args
[0]);
3212 buf
= grub_malloc(file
->size
+ 1);
3218 buf
[file
->size
] = 0;
3219 grub_file_read(file
, buf
, file
->size
);
3221 if (grub_strstr(buf
, args
[1]))
3228 grub_check_free(buf
);
3229 grub_file_close(file
);
3234 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3239 ventoy_iso9660_vd pvd
;
3246 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3249 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3252 debug("failed to open file %s\n", args
[0]);
3256 grub_file_seek(file
, 16 * 2048);
3257 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3258 if (len
!= sizeof(pvd
))
3260 debug("failed to read pvd %d\n", len
);
3264 grub_memset(buf
, 0, sizeof(buf
));
3265 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3266 ventoy_set_env(args
[1], buf
);
3268 grub_memset(buf
, 0, sizeof(buf
));
3269 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3270 ventoy_set_env(args
[2], buf
);
3273 grub_file_close(file
);
3278 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3289 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3292 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3295 debug("failed to open file %s\n", args
[0]);
3299 grub_memset(buf
, 0, sizeof(buf
));
3300 grub_file_seek(file
, 16 * 2048 + 813);
3301 len
= (int)grub_file_read(file
, buf
, 17);
3304 debug("failed to read create date %d\n", len
);
3308 ventoy_set_env(args
[1], buf
);
3311 grub_file_close(file
);
3316 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3322 ventoy_env_hook_root(1);
3327 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3333 ventoy_env_hook_root(0);
3338 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3345 int image_sector_size
;
3347 ventoy_chain_head
*chain
;
3348 ventoy_img_chunk
*chunk
;
3349 ventoy_os_param
*osparam
;
3350 ventoy_image_location
*location
;
3351 ventoy_image_disk_region
*region
;
3352 struct grub_acpi_table_header
*acpi
;
3361 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3363 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3369 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3371 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3373 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3377 img_chunk_num
= chain
->img_chunk_num
;
3379 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3380 datalen
= sizeof(ventoy_os_param
) + loclen
;
3382 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3383 acpi
= grub_zalloc(buflen
);
3389 /* Step1: Fill acpi table header */
3390 grub_memcpy(acpi
->signature
, "VTOY", 4);
3391 acpi
->length
= buflen
;
3393 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3394 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3396 acpi
->creator_id
[0] = 1;
3397 acpi
->creator_rev
= 1;
3399 /* Step2: Fill data */
3400 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3401 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3402 osparam
->vtoy_img_location_addr
= 0;
3403 osparam
->vtoy_img_location_len
= loclen
;
3404 osparam
->chksum
= 0;
3405 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3407 location
= (ventoy_image_location
*)(osparam
+ 1);
3408 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3409 location
->image_sector_size
= image_sector_size
;
3410 location
->disk_sector_size
= chain
->disk_sector_size
;
3411 location
->region_count
= img_chunk_num
;
3413 region
= location
->regions
;
3414 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3415 if (512 == image_sector_size
)
3417 for (i
= 0; i
< img_chunk_num
; i
++)
3419 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3420 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3421 region
->disk_start_sector
= chunk
->disk_start_sector
;
3428 for (i
= 0; i
< img_chunk_num
; i
++)
3430 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3431 region
->image_start_sector
= chunk
->img_start_sector
;
3432 region
->disk_start_sector
= chunk
->disk_start_sector
;
3438 /* Step3: Fill acpi checksum */
3440 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3442 /* load acpi table */
3443 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3444 grub_script_execute_sourcecode(cmd
);
3448 VENTOY_CMD_RETURN(0);
3451 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3457 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3458 g_ventoy_last_entry
= -1;
3463 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3469 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3474 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3476 grub_uint64_t sectors
;
3478 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3480 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3484 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3487 return sectors
* 512;
3490 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3492 const char *pos
= filename
+ 1;
3500 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3502 grub_strncpy((char *)data
, filename
, 128);
3513 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3516 char *device_name
= NULL
;
3517 grub_device_t dev
= NULL
;
3518 grub_fs_t fs
= NULL
;
3519 char buf
[128] = {0};
3525 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3529 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3531 device_name
= grub_file_get_device_name(args
[0]);
3534 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3538 dev
= grub_device_open(device_name
);
3541 debug("grub_device_open failed, %s\n", device_name
);
3545 fs
= grub_fs_probe(dev
);
3548 debug("grub_fs_probe failed, %s\n", device_name
);
3552 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3556 ventoy_set_env(args
[2], buf
);
3563 check_free(device_name
, grub_free
);
3564 check_free(dev
, grub_device_close
);
3569 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3579 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3580 if (!g_ventoy_part_info
)
3585 disk
= grub_disk_open(args
[0]);
3588 debug("Failed to open disk %s\n", args
[0]);
3592 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3594 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3595 grub_disk_close(disk
);
3597 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3598 dev
= grub_device_open(name
);
3601 /* make sure that we are running in a correct Ventoy device */
3602 ret
= ventoy_check_device(dev
);
3603 grub_device_close(dev
);
3614 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3617 grub_uint8_t zeroguid
[16] = {0};
3622 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3625 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3627 if (id
>= 1 && id
<= 128)
3629 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3637 if (id
>= 1 && id
<= 4)
3639 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3649 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3652 char *device_name
= NULL
;
3653 grub_device_t dev
= NULL
;
3654 grub_fs_t fs
= NULL
;
3661 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3665 device_name
= grub_file_get_device_name(args
[0]);
3668 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3672 dev
= grub_device_open(device_name
);
3675 debug("grub_device_open failed, %s\n", device_name
);
3679 fs
= grub_fs_probe(dev
);
3682 debug("grub_fs_probe failed, %s\n", device_name
);
3686 fs
->fs_label(dev
, &label
);
3689 ventoy_set_env(args
[1], label
);
3697 check_free(device_name
, grub_free
);
3698 check_free(dev
, grub_device_close
);
3703 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3707 grub_snprintf((char *)data
, 256, "%s", filename
);
3715 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3718 char *device_name
= NULL
;
3719 grub_device_t dev
= NULL
;
3720 grub_fs_t fs
= NULL
;
3721 char name
[256] ={0};
3727 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3731 device_name
= grub_file_get_device_name(args
[0]);
3734 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3738 dev
= grub_device_open(device_name
);
3741 debug("grub_device_open failed, %s\n", device_name
);
3745 fs
= grub_fs_probe(dev
);
3748 debug("grub_fs_probe failed, %s\n", device_name
);
3752 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3755 ventoy_set_env(args
[2], name
);
3762 check_free(device_name
, grub_free
);
3763 check_free(dev
, grub_device_close
);
3768 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3778 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3782 for (pos
= args
[0]; *pos
; pos
++)
3796 grub_env_set(args
[1], args
[0]);
3806 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3808 struct grub_video_mode_info info
;
3815 if (!g_video_mode_list
)
3817 ventoy_enum_video_mode();
3820 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3822 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3826 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3829 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3831 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3832 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3834 VENTOY_CMD_RETURN(0);
3837 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3839 struct grub_video_mode_info info
;
3846 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3848 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3852 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3855 grub_env_set(args
[0], buf
);
3857 VENTOY_CMD_RETURN(0);
3860 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3868 if (!g_video_mode_list
)
3873 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3874 if (id
< g_video_mode_num
)
3876 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3877 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3880 grub_env_set(args
[1], buf
);
3882 VENTOY_CMD_RETURN(0);
3885 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3887 grub_uint64_t size
= 0;
3890 char fullpath
[256] = {0};
3893 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3896 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3899 debug("grub_file_open failed <%s>\n", fullpath
);
3905 grub_file_close(file
);
3909 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3913 char fullpath
[256] = {0};
3916 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3919 file
= grub_file_open(fullpath
, type
);
3922 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3929 int ventoy_is_file_exist(const char *fmt
, ...)
3934 char buf
[256] = {0};
3936 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3940 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3943 grub_strncpy(pos
+ len
, "\" ]", 3);
3945 debug("script exec %s\n", buf
);
3947 if (0 == grub_script_execute_sourcecode(buf
))
3955 int ventoy_is_dir_exist(const char *fmt
, ...)
3960 char buf
[256] = {0};
3962 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
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_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
3984 grub_uint8_t
*outbuf
;
3985 grub_uint8_t gzHdr
[10] =
3987 0x1F, 0x8B, /* magic */
3990 0,0,0,0, /* mtime */
3995 grub_memset(&s
, 0, sizeof(mz_stream
));
3997 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
3999 outbuf
= (grub_uint8_t
*)mem_out
;
4001 mem_out_len
-= sizeof(gzHdr
) + 8;
4002 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
4003 outbuf
+= sizeof(gzHdr
);
4005 s
.avail_in
= mem_in_len
;
4008 s
.avail_out
= mem_out_len
;
4009 s
.next_out
= outbuf
;
4011 mz_deflate(&s
, MZ_FINISH
);
4015 outbuf
+= s
.total_out
;
4016 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
4017 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
4019 return s
.total_out
+ sizeof(gzHdr
) + 8;
4022 static int ventoy_env_init(void)
4026 grub_env_set("vtdebug_flag", "");
4028 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4029 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4030 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4031 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4033 ventoy_filt_register(0, ventoy_wrapper_open
);
4035 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4038 g_grub_param
->grub_env_get
= grub_env_get
;
4039 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4040 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4041 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4042 grub_env_set("env_param", buf
);
4043 grub_env_set("ventoy_env_param", buf
);
4044 grub_env_export("ventoy_env_param");
4050 static cmd_para ventoy_cmds
[] =
4052 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4053 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4054 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4055 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4056 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4057 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4058 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4059 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4060 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4061 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4062 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4063 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4064 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4065 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4066 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4067 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4068 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4069 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4070 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4071 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4073 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4074 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4075 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4076 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4077 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4078 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4079 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4081 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4082 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4083 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4084 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4085 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4086 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4087 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4088 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4091 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4092 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4093 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4094 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4095 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4096 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4097 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4098 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4099 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4100 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4101 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4103 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4104 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4105 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4106 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4107 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4108 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4110 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4111 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4112 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4113 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4114 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4115 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4116 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4117 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4118 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4119 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4121 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4122 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4123 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4124 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4125 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4126 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4127 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4128 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4130 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4131 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4132 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4135 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4136 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4137 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4139 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4140 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4141 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4144 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4145 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4146 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4147 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4148 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4149 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4150 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4151 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4152 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4153 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4155 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4156 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4157 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4163 GRUB_MOD_INIT(ventoy
)
4166 cmd_para
*cur
= NULL
;
4170 ventoy_arch_mode_init();
4172 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4174 cur
= ventoy_cmds
+ i
;
4175 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4176 cur
->summary
, cur
->description
, cur
->parser
);
4180 GRUB_MOD_FINI(ventoy
)
4184 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4186 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);