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
)
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
)
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
)
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
);
1280 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1285 img
= grub_zalloc(sizeof(img_info
));
1289 img
->plugin_list_index
= index
;
1290 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1292 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1294 img
->size
= info
->size
;
1297 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1300 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1302 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1307 if (g_ventoy_img_list
)
1309 tail
= *(node
->tail
);
1315 g_ventoy_img_list
= img
;
1318 img
->id
= g_ventoy_img_count
;
1320 if (node
&& NULL
== node
->firstiso
)
1322 node
->firstiso
= img
;
1333 *((img_info
**)(node
->tail
)) = img
;
1334 g_ventoy_img_count
++;
1336 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1337 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1340 img
->class = g_menu_class
[type
];
1342 img
->menu_prefix
= g_menu_prefix
[type
];
1344 if (img_type_iso
== type
)
1346 if (ventoy_plugin_check_memdisk(img
->path
))
1348 img
->menu_prefix
= "miso";
1352 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1359 static int ventoy_arch_mode_init(void)
1361 #ifdef GRUB_MACHINE_EFI
1362 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1364 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1365 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1367 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1369 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1370 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1374 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1375 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1378 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1379 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1385 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1387 int len
= GRUB_UINT_MAX
;
1388 const char *value
= NULL
;
1389 char name
[32] = {0};
1390 char plat
[32] = {0};
1391 char guidstr
[32] = {0};
1392 ventoy_guid guid
= VENTOY_GUID
;
1393 const char *fmt1
= NULL
;
1394 const char *fmt2
= NULL
;
1395 const char *fmt3
= NULL
;
1396 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1397 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1398 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1399 const char fmtcode
[]={
1400 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1401 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1402 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1403 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1404 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1405 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1408 grub_memset(name
, 0, sizeof(name
));
1409 puint
[0] = grub_swap_bytes32(0x56454e54);
1410 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1411 puint
[2] = grub_swap_bytes32(0x45525349);
1412 puint
[1] = grub_swap_bytes32(0x4f595f56);
1413 value
= ventoy_get_env(name
);
1415 grub_memset(name
, 0, sizeof(name
));
1416 puint
[1] = grub_swap_bytes32(0x5f544f50);
1417 puint
[0] = grub_swap_bytes32(0x56544c45);
1418 fmt1
= ventoy_get_env(name
);
1424 grub_memset(name
, 0, sizeof(name
));
1425 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1426 puint
[0] = grub_swap_bytes32(0x56544c45);
1427 fmt2
= ventoy_get_env(name
);
1429 grub_memset(name
, 0, sizeof(name
));
1430 puint
[1] = grub_swap_bytes32(0x5f434c52);
1431 puint
[0] = grub_swap_bytes32(0x56544c45);
1432 fmt3
= ventoy_get_env(name
);
1434 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1436 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1438 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1439 #pragma GCC diagnostic push
1440 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1441 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1442 fmt1
? fmt1
: fmtdata
,
1443 fmt2
? fmt2
: fmtdata
+ 4,
1444 value
? value
: "", plat
, guidstr
,
1445 fmt3
? fmt3
: fmtdata
+ 6);
1446 #pragma GCC diagnostic pop
1448 grub_memset(name
, 0, sizeof(name
));
1449 puint
[0] = grub_swap_bytes32(0x76746f79);
1450 puint
[2] = grub_swap_bytes32(0x656e7365);
1451 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1452 ventoy_set_env(name
, guidstr
);
1457 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1461 grub_uint8_t md5
[16];
1465 grub_memset(input
, 0, sizeof(input
));
1467 grub_printf("Enter password: ");
1470 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1472 grub_password_get(input
, 128);
1473 if (grub_strcmp(pwd
->text
, input
) == 0)
1478 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1480 grub_password_get(input
, 128);
1481 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1482 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1487 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1489 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1490 grub_password_get(input
+ offset
, 128);
1492 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1493 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1499 grub_printf("Invalid password!\n\n");
1506 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1508 img_info
*minimg
= NULL
;
1509 img_info
*img
= (img_info
*)(node
->firstiso
);
1511 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1513 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1528 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1530 img_iterator_node
*Minchild
= NULL
;
1531 img_iterator_node
*child
= node
->firstchild
;
1533 while (child
&& child
->parent
== node
)
1535 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1539 child
= child
->next
;
1544 Minchild
->select
= 1;
1550 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1553 img_info
*img
= NULL
;
1554 const char *dir_class
= NULL
;
1555 const char *dir_alias
= NULL
;
1556 img_iterator_node
*child
= NULL
;
1558 if (node
->isocnt
== 0 || node
->done
== 1)
1563 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1565 offset
= node
->parent
->dirlen
;
1568 if (node
== &g_img_iterator_head
)
1570 if (g_default_menu_mode
== 0)
1572 if (g_tree_view_menu_style
== 0)
1574 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1575 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1576 " echo 'return ...' \n"
1581 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1582 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1590 node
->dir
[node
->dirlen
- 1] = 0;
1591 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1594 dir_class
= "vtoydir";
1597 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1600 if (g_tree_view_menu_style
== 0)
1602 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1603 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1604 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1608 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1609 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1610 dir_alias
, dir_class
, node
->dir
+ offset
);
1615 dir_alias
= node
->dir
+ offset
;
1617 if (g_tree_view_menu_style
== 0)
1619 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1620 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1621 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1625 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1626 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1627 dir_alias
, dir_class
, node
->dir
+ offset
);
1631 if (g_tree_view_menu_style
== 0)
1633 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1634 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1635 " echo 'return ...' \n"
1640 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1641 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1647 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1649 ventoy_dynamic_tree_menu(child
);
1652 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1654 if (g_tree_view_menu_style
== 0)
1656 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1657 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1660 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1661 img
->unsupport
? "[***********] " : "",
1662 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1664 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1668 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1669 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1672 img
->unsupport
? "[***********] " : "",
1673 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1675 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1679 if (node
!= &g_img_iterator_head
)
1681 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1688 int ventoy_check_device_result(int ret
)
1692 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1693 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1694 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1698 grub_printf(VTOY_WARNING
"\n");
1699 grub_printf(VTOY_WARNING
"\n");
1700 grub_printf(VTOY_WARNING
"\n\n\n");
1702 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1703 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1705 grub_printf("\n\nWill exit after 10 seconds ...... ");
1713 int ventoy_check_device(grub_device_t dev
)
1717 grub_uint64_t offset
;
1722 struct grub_partition
*partition
;
1724 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1726 return ventoy_check_device_result(1 | 0x1000);
1729 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1730 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1731 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1733 #ifndef GRUB_MACHINE_EFI
1734 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1735 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1736 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1738 return ventoy_check_device_result(2 | 0x1000);
1747 /* We must have partition 2 */
1750 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1754 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1758 return ventoy_check_device_result(3 | 0x1000);
1761 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1763 grub_file_close(file
);
1764 return ventoy_check_device_result(4 | 0x1000);
1767 partition
= dev
->disk
->partition
;
1768 if (partition
->number
!= 0 || partition
->start
!= 2048)
1770 return ventoy_check_device_result(5);
1775 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
1777 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
1778 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
1779 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
1781 grub_file_close(file
);
1782 return ventoy_check_device_result(6);
1787 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1788 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1789 PartTbl
[1].SectorCount
!= 65536)
1791 grub_file_close(file
);
1792 return ventoy_check_device_result(6);
1798 offset
= partition
->start
+ partition
->len
;
1799 partition
= file
->device
->disk
->partition
;
1800 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1802 grub_file_close(file
);
1803 return ventoy_check_device_result(7);
1807 grub_file_close(file
);
1809 if (workaround
== 0)
1811 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1812 dev2
= grub_device_open(devname
);
1815 return ventoy_check_device_result(8);
1818 fs
= grub_fs_probe(dev2
);
1821 grub_device_close(dev2
);
1822 return ventoy_check_device_result(9);
1825 fs
->fs_label(dev2
, &label
);
1826 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1828 grub_device_close(dev2
);
1829 return ventoy_check_device_result(10);
1832 grub_device_close(dev2
);
1835 return ventoy_check_device_result(0);
1838 static int ventoy_set_default_menu(void)
1844 const char *strdata
= NULL
;
1845 img_info
*cur
= NULL
;
1846 img_info
*default_node
= NULL
;
1847 const char *default_image
= NULL
;
1849 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1850 if (default_image
&& default_image
[0] == '/')
1852 img_len
= grub_strlen(default_image
);
1854 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1856 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1868 if (0 == g_default_menu_mode
)
1870 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1874 def
= grub_strdup(default_image
);
1880 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1882 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1883 if (strdata
&& strdata
[0] == '/')
1885 pos
= def
+ grub_strlen(strdata
);
1896 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1899 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1903 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1911 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1915 grub_device_t dev
= NULL
;
1916 img_info
*cur
= NULL
;
1917 img_info
*tail
= NULL
;
1918 const char *strdata
= NULL
;
1919 char *device_name
= NULL
;
1921 img_iterator_node
*node
= NULL
;
1922 img_iterator_node
*tmp
= NULL
;
1928 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1931 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1933 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1936 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1937 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1939 g_filt_dot_underscore_file
= 1;
1942 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1943 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1945 g_sort_case_sensitive
= 1;
1948 device_name
= grub_file_get_device_name(args
[0]);
1954 g_enum_dev
= dev
= grub_device_open(device_name
);
1960 g_enum_fs
= fs
= grub_fs_probe(dev
);
1966 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1968 debug("unsupported fs:<%s>\n", fs
->name
);
1969 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1973 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1975 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1976 if (strdata
&& strdata
[0] == '1')
1978 g_default_menu_mode
= 1;
1981 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1983 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1985 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1986 if (strdata
&& strdata
[0] == '/')
1988 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1989 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1991 g_img_iterator_head
.dir
[len
++] = '/';
1993 g_img_iterator_head
.dirlen
= len
;
1997 g_img_iterator_head
.dirlen
= 1;
1998 grub_strcpy(g_img_iterator_head
.dir
, "/");
2001 g_img_iterator_head
.tail
= &tail
;
2003 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2005 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
2008 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2009 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2011 g_tree_view_menu_style
= 1;
2014 ventoy_set_default_menu();
2016 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2018 ventoy_dynamic_tree_menu(node
);
2022 node
= g_img_iterator_head
.next
;
2030 /* sort image list by image name */
2031 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2033 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2035 if (ventoy_cmp_img(cur
, tail
) > 0)
2037 ventoy_swap_img(cur
, tail
);
2042 if (g_default_menu_mode
== 1)
2044 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2045 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2046 " echo 'return ...' \n"
2050 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2052 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2053 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2056 cur
->unsupport
? "[***********] " : "",
2057 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2059 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2062 g_tree_script_buf
[g_tree_script_pos
] = 0;
2063 g_list_script_buf
[g_list_script_pos
] = 0;
2065 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2066 grub_env_set(args
[1], buf
);
2070 check_free(device_name
, grub_free
);
2071 check_free(dev
, grub_device_close
);
2073 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2077 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2079 img_info
*next
= NULL
;
2080 img_info
*cur
= g_ventoy_img_list
;
2093 g_ventoy_img_list
= NULL
;
2094 g_ventoy_img_count
= 0;
2096 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2099 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2102 img_info
*cur
= g_ventoy_img_list
;
2106 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2108 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2111 img_id
= grub_strtol(args
[0], NULL
, 10);
2112 if (img_id
>= g_ventoy_img_count
)
2114 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2117 debug("Find image %ld name \n", img_id
);
2119 while (cur
&& img_id
> 0)
2127 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2130 debug("image name is %s\n", cur
->name
);
2132 grub_env_set(args
[1], cur
->name
);
2134 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2137 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2142 const char *id
= NULL
;
2143 img_info
*cur
= g_ventoy_img_list
;
2147 if (argc
< 1 || argc
> 2)
2149 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2152 id
= grub_env_get("chosen");
2154 pos
= grub_strstr(id
, "VID_");
2157 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2161 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2166 if (img_id
== cur
->id
)
2175 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2178 grub_env_set(args
[0], cur
->path
);
2182 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2183 grub_env_set(args
[1], value
);
2186 g_svd_replace_offset
= 0;
2188 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2191 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2198 device_name
= grub_file_get_device_name(filename
);
2210 pos2
= grub_strstr(pos
, ",");
2213 pos2
= grub_strstr(pos
, ")");
2221 disk
= grub_disk_open(pos
);
2224 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2225 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2226 grub_disk_close(disk
);
2233 grub_free(device_name
);
2237 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2239 eltorito_descriptor desc
;
2241 grub_memset(&desc
, 0, sizeof(desc
));
2242 grub_file_seek(file
, 17 * 2048);
2243 grub_file_read(file
, &desc
, sizeof(desc
));
2245 if (desc
.type
!= 0 || desc
.version
!= 1)
2250 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2251 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2259 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2263 grub_uint8_t buf
[512];
2265 grub_file_seek(file
, sector
* 2048);
2266 grub_file_read(file
, buf
, sizeof(buf
));
2268 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2270 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2274 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2279 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2281 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2283 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2287 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2289 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2294 debug("%s does not contain efi eltorito\n", file
->name
);
2298 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2301 const char *fs
= NULL
;
2302 const char *cdprompt
= NULL
;
2304 grub_uint8_t chksum
= 0;
2307 disk
= file
->device
->disk
;
2308 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2310 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2311 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2312 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2314 pos
= grub_strstr(file
->name
, "/");
2320 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2322 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2324 param
->vtoy_img_size
= file
->size
;
2326 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2327 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2329 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2331 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2332 param
->vtoy_reserved
[4] = 0;
2333 if (g_ventoy_chain_type
== 1) /* Windows */
2335 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2336 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2338 param
->vtoy_reserved
[4] = 1;
2342 fs
= ventoy_get_env("ventoy_fs_probe");
2343 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2345 param
->vtoy_reserved
[3] = 1;
2348 /* calculate checksum */
2349 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2351 chksum
+= *((grub_uint8_t
*)param
+ i
);
2353 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2358 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2360 grub_uint32_t i
= 0;
2361 grub_uint64_t total
= 0;
2362 ventoy_img_chunk
*chunk
= NULL
;
2364 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2366 chunk
= chunklist
->chunk
+ i
;
2368 if (chunk
->disk_start_sector
<= start
)
2370 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2374 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2377 if (total
!= ((file
->size
+ 511) / 512))
2379 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2386 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2390 grub_uint32_t i
= 0;
2391 grub_uint32_t sector
= 0;
2392 grub_uint32_t count
= 0;
2393 grub_off_t size
= 0;
2394 grub_off_t read
= 0;
2396 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2397 if (fs_type
== ventoy_fs_exfat
)
2399 grub_fat_get_file_chunk(start
, file
, chunklist
);
2401 else if (fs_type
== ventoy_fs_ext
)
2403 grub_ext_get_file_chunk(start
, file
, chunklist
);
2407 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2408 file
->read_hook_data
= chunklist
;
2410 for (size
= file
->size
; size
> 0; size
-= read
)
2412 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2413 grub_file_read(file
, NULL
, read
);
2416 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2418 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2419 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2422 if (ventoy_fs_udf
== fs_type
)
2424 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2426 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2427 chunklist
->chunk
[i
].img_start_sector
= sector
;
2428 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2434 len
= (int)grub_strlen(file
->name
);
2435 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2436 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2437 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2438 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2440 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2442 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2452 chunklist
->chunk
[i
].img_start_sector
= sector
;
2453 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2461 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2465 grub_disk_addr_t start
;
2470 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2473 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2476 g_conf_replace_node
= NULL
;
2477 g_conf_replace_offset
= 0;
2479 if (g_img_chunk_list
.chunk
)
2481 grub_free(g_img_chunk_list
.chunk
);
2484 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2486 grub_file_close(file
);
2487 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2490 /* get image chunk data */
2491 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2492 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2493 if (NULL
== g_img_chunk_list
.chunk
)
2495 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2498 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2499 g_img_chunk_list
.cur_chunk
= 0;
2501 start
= file
->device
->disk
->partition
->start
;
2503 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2505 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2506 grub_file_close(file
);
2510 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2513 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2514 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2517 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2519 grub_uint64_t offset
= 0;
2520 grub_uint32_t align
= 0;
2521 grub_file_t file
= NULL
;
2522 conf_replace
*node
= NULL
;
2528 debug("select conf replace argc:%d\n", argc
);
2535 node
= ventoy_plugin_find_conf_replace(args
[1]);
2538 debug("Conf replace not found for %s\n", args
[1]);
2542 debug("Find conf replace for %s\n", args
[1]);
2544 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2547 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2551 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2552 grub_file_close(file
);
2554 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2557 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2561 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2563 if (align
> vtoy_max_replace_file_size
)
2565 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2569 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2570 g_conf_replace_new_len
= (int)file
->size
;
2571 g_conf_replace_new_len_align
= align
;
2573 g_conf_replace_node
= node
;
2574 g_conf_replace_offset
= offset
+ 2;
2576 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2581 grub_file_close(file
);
2583 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2586 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2591 char configfile
[128];
2592 install_template
*node
= NULL
;
2598 debug("select auto installation argc:%d\n", argc
);
2605 node
= ventoy_plugin_find_install_template(args
[0]);
2608 debug("Auto install template not found for %s\n", args
[0]);
2612 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2614 node
->cursel
= node
->autosel
- 1;
2615 debug("Auto install template auto select %d\n", node
->autosel
);
2619 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2625 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2626 " echo %s\n}\n", "123");
2628 for (i
= 0; i
< node
->templatenum
; i
++)
2630 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2632 node
->templatepath
[i
].path
);
2635 g_ventoy_menu_esc
= 1;
2636 g_ventoy_suppress_esc
= 1;
2638 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2639 grub_script_execute_sourcecode(configfile
);
2641 g_ventoy_menu_esc
= 0;
2642 g_ventoy_suppress_esc
= 0;
2646 node
->cursel
= g_ventoy_last_entry
- 1;
2648 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2651 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2656 char configfile
[128];
2657 persistence_config
*node
;
2663 debug("select persistence argc:%d\n", argc
);
2670 node
= ventoy_plugin_find_persistent(args
[0]);
2673 debug("Persistence image not found for %s\n", args
[0]);
2677 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2679 node
->cursel
= node
->autosel
- 1;
2680 debug("Persistence image auto select %d\n", node
->autosel
);
2684 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2690 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2691 " echo %s\n}\n", "123");
2693 for (i
= 0; i
< node
->backendnum
; i
++)
2695 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2697 node
->backendpath
[i
].path
);
2701 g_ventoy_menu_esc
= 1;
2702 g_ventoy_suppress_esc
= 1;
2704 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2705 grub_script_execute_sourcecode(configfile
);
2707 g_ventoy_menu_esc
= 0;
2708 g_ventoy_suppress_esc
= 0;
2712 node
->cursel
= g_ventoy_last_entry
- 1;
2714 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2717 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2720 ventoy_img_chunk
*cur
;
2726 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2728 cur
= g_img_chunk_list
.chunk
+ i
;
2729 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2730 cur
->img_start_sector
, cur
->img_end_sector
,
2731 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2735 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2738 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2742 ventoy_img_chunk_list chunklist
;
2747 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2750 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2753 /* get image chunk data */
2754 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2755 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2756 if (NULL
== chunklist
.chunk
)
2758 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2761 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2762 chunklist
.cur_chunk
= 0;
2764 ventoy_get_block_list(file
, &chunklist
, 0);
2766 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2768 grub_printf("########## UNSUPPORTED ###############\n");
2771 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2773 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2775 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2776 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2779 grub_printf("\n==================================\n");
2781 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2783 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2784 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2785 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2786 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2787 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2791 grub_free(chunklist
.chunk
);
2792 grub_file_close(file
);
2794 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2797 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2800 ventoy_grub_param_file_replace
*replace
= NULL
;
2808 replace
= &(g_grub_param
->file_replace
);
2809 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2811 replace
->old_name_cnt
= 0;
2812 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2814 replace
->old_name_cnt
++;
2815 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2818 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2821 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2824 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2832 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2833 grub_printf("%s", g_list_script_buf
);
2837 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2838 grub_printf("%s", g_tree_script_buf
);
2844 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2846 img_info
*cur
= g_ventoy_img_list
;
2854 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2855 grub_printf("name:<%s>\n\n", cur
->name
);
2862 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2868 ventoy_plugin_dump_injection();
2873 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2879 ventoy_plugin_dump_auto_install();
2884 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2890 ventoy_plugin_dump_persistence();
2895 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2906 if (args
[0][0] == '0')
2908 return g_ventoy_memdisk_mode
? 0 : 1;
2910 else if (args
[0][0] == '1')
2912 return g_ventoy_iso_raw
? 0 : 1;
2914 else if (args
[0][0] == '2')
2916 return g_ventoy_iso_uefi_drv
? 0 : 1;
2922 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2924 static int configfile_mode
= 0;
2925 char memfile
[128] = {0};
2932 * args[0]: 0:normal 1:configfile
2933 * args[1]: 0:list_buf 1:tree_buf
2938 debug("Invalid argc %d\n", argc
);
2942 if (args
[0][0] == '0')
2944 if (args
[1][0] == '0')
2946 grub_script_execute_sourcecode(g_list_script_buf
);
2950 grub_script_execute_sourcecode(g_tree_script_buf
);
2955 if (configfile_mode
)
2957 debug("Now already in F3 mode %d\n", configfile_mode
);
2961 if (args
[1][0] == '0')
2963 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2964 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2968 g_ventoy_last_entry
= -1;
2969 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2970 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2973 configfile_mode
= 1;
2974 grub_script_execute_sourcecode(memfile
);
2975 configfile_mode
= 0;
2981 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2992 g_ventoy_case_insensitive
= 1;
2993 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2994 g_ventoy_case_insensitive
= 0;
3000 grub_file_close(file
);
3006 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3011 const char *isopath
= NULL
;
3013 ventoy_mbr_head mbr
;
3020 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3023 isopath
= grub_env_get("vtoy_iso_part");
3026 debug("isopath is null %p\n", isopath
);
3030 debug("isopath is %s\n", isopath
);
3032 for (id
= 0; id
< 30 && (find
== 0); id
++)
3034 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3035 if (grub_strstr(isopath
, hdname
))
3037 debug("skip %s ...\n", hdname
);
3041 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3043 disk
= grub_disk_open(hdname
);
3046 debug("%s not exist\n", hdname
);
3050 grub_memset(&mbr
, 0, sizeof(mbr
));
3051 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3053 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3055 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3056 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3059 grub_env_set(args
[0], hdname
);
3063 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3067 debug("read %s failed\n", hdname
);
3070 grub_disk_close(disk
);
3076 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3087 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3090 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3093 debug("failed to open file %s\n", args
[0]);
3097 buf
= grub_malloc(len
);
3104 grub_file_read(file
, buf
, len
- 1);
3106 ventoy_get_line(buf
);
3107 ventoy_set_env(args
[1], buf
);
3111 grub_check_free(buf
);
3112 grub_file_close(file
);
3117 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3122 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3123 "0 %llu linear /dev/ventoy %llu\n",
3124 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3129 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3131 char *device_name
= NULL
;
3132 grub_device_t dev
= NULL
;
3137 g_part_list_pos
= 0;
3138 grub_env_unset("vtoy_img_part_file");
3145 device_name
= grub_file_get_device_name(args
[0]);
3148 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3152 dev
= grub_device_open(device_name
);
3155 debug("grub_device_open failed, %s\n", device_name
);
3159 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3161 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3162 grub_env_set("vtoy_img_part_file", buf
);
3166 check_free(device_name
, grub_free
);
3167 check_free(dev
, grub_device_close
);
3173 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3184 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3187 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3190 debug("failed to open file %s\n", args
[0]);
3194 buf
= grub_malloc(file
->size
+ 1);
3200 buf
[file
->size
] = 0;
3201 grub_file_read(file
, buf
, file
->size
);
3203 if (grub_strstr(buf
, args
[1]))
3210 grub_check_free(buf
);
3211 grub_file_close(file
);
3216 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3221 ventoy_iso9660_vd pvd
;
3228 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3231 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3234 debug("failed to open file %s\n", args
[0]);
3238 grub_file_seek(file
, 16 * 2048);
3239 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3240 if (len
!= sizeof(pvd
))
3242 debug("failed to read pvd %d\n", len
);
3246 grub_memset(buf
, 0, sizeof(buf
));
3247 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3248 ventoy_set_env(args
[1], buf
);
3250 grub_memset(buf
, 0, sizeof(buf
));
3251 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3252 ventoy_set_env(args
[2], buf
);
3255 grub_file_close(file
);
3260 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3271 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3274 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3277 debug("failed to open file %s\n", args
[0]);
3281 grub_memset(buf
, 0, sizeof(buf
));
3282 grub_file_seek(file
, 16 * 2048 + 813);
3283 len
= (int)grub_file_read(file
, buf
, 17);
3286 debug("failed to read create date %d\n", len
);
3290 ventoy_set_env(args
[1], buf
);
3293 grub_file_close(file
);
3298 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3304 ventoy_env_hook_root(1);
3309 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3315 ventoy_env_hook_root(0);
3320 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3327 int image_sector_size
;
3329 ventoy_chain_head
*chain
;
3330 ventoy_img_chunk
*chunk
;
3331 ventoy_os_param
*osparam
;
3332 ventoy_image_location
*location
;
3333 ventoy_image_disk_region
*region
;
3334 struct grub_acpi_table_header
*acpi
;
3343 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3345 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3351 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3353 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3355 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3359 img_chunk_num
= chain
->img_chunk_num
;
3361 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3362 datalen
= sizeof(ventoy_os_param
) + loclen
;
3364 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3365 acpi
= grub_zalloc(buflen
);
3371 /* Step1: Fill acpi table header */
3372 grub_memcpy(acpi
->signature
, "VTOY", 4);
3373 acpi
->length
= buflen
;
3375 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3376 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3378 acpi
->creator_id
[0] = 1;
3379 acpi
->creator_rev
= 1;
3381 /* Step2: Fill data */
3382 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3383 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3384 osparam
->vtoy_img_location_addr
= 0;
3385 osparam
->vtoy_img_location_len
= loclen
;
3386 osparam
->chksum
= 0;
3387 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3389 location
= (ventoy_image_location
*)(osparam
+ 1);
3390 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3391 location
->image_sector_size
= image_sector_size
;
3392 location
->disk_sector_size
= chain
->disk_sector_size
;
3393 location
->region_count
= img_chunk_num
;
3395 region
= location
->regions
;
3396 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3397 if (512 == image_sector_size
)
3399 for (i
= 0; i
< img_chunk_num
; i
++)
3401 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3402 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3403 region
->disk_start_sector
= chunk
->disk_start_sector
;
3410 for (i
= 0; i
< img_chunk_num
; i
++)
3412 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3413 region
->image_start_sector
= chunk
->img_start_sector
;
3414 region
->disk_start_sector
= chunk
->disk_start_sector
;
3420 /* Step3: Fill acpi checksum */
3422 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3424 /* load acpi table */
3425 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3426 grub_script_execute_sourcecode(cmd
);
3430 VENTOY_CMD_RETURN(0);
3433 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3439 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3440 g_ventoy_last_entry
= -1;
3445 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3451 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3456 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3458 grub_uint64_t sectors
;
3460 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3462 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3466 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3469 return sectors
* 512;
3472 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3474 const char *pos
= filename
+ 1;
3482 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3484 grub_strncpy((char *)data
, filename
, 128);
3495 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3498 char *device_name
= NULL
;
3499 grub_device_t dev
= NULL
;
3500 grub_fs_t fs
= NULL
;
3501 char buf
[128] = {0};
3507 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3511 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3513 device_name
= grub_file_get_device_name(args
[0]);
3516 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3520 dev
= grub_device_open(device_name
);
3523 debug("grub_device_open failed, %s\n", device_name
);
3527 fs
= grub_fs_probe(dev
);
3530 debug("grub_fs_probe failed, %s\n", device_name
);
3534 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3538 ventoy_set_env(args
[2], buf
);
3545 check_free(device_name
, grub_free
);
3546 check_free(dev
, grub_device_close
);
3551 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3561 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3562 if (!g_ventoy_part_info
)
3567 disk
= grub_disk_open(args
[0]);
3570 debug("Failed to open disk %s\n", args
[0]);
3574 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3576 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3577 grub_disk_close(disk
);
3579 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3580 dev
= grub_device_open(name
);
3583 /* make sure that we are running in a correct Ventoy device */
3584 ret
= ventoy_check_device(dev
);
3585 grub_device_close(dev
);
3596 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3599 grub_uint8_t zeroguid
[16] = {0};
3604 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3607 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3609 if (id
>= 1 && id
<= 128)
3611 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3619 if (id
>= 1 && id
<= 4)
3621 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3631 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3634 char *device_name
= NULL
;
3635 grub_device_t dev
= NULL
;
3636 grub_fs_t fs
= NULL
;
3643 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3647 device_name
= grub_file_get_device_name(args
[0]);
3650 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3654 dev
= grub_device_open(device_name
);
3657 debug("grub_device_open failed, %s\n", device_name
);
3661 fs
= grub_fs_probe(dev
);
3664 debug("grub_fs_probe failed, %s\n", device_name
);
3668 fs
->fs_label(dev
, &label
);
3671 ventoy_set_env(args
[1], label
);
3679 check_free(device_name
, grub_free
);
3680 check_free(dev
, grub_device_close
);
3685 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3689 grub_snprintf((char *)data
, 256, "%s", filename
);
3697 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3700 char *device_name
= NULL
;
3701 grub_device_t dev
= NULL
;
3702 grub_fs_t fs
= NULL
;
3703 char name
[256] ={0};
3709 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3713 device_name
= grub_file_get_device_name(args
[0]);
3716 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3720 dev
= grub_device_open(device_name
);
3723 debug("grub_device_open failed, %s\n", device_name
);
3727 fs
= grub_fs_probe(dev
);
3730 debug("grub_fs_probe failed, %s\n", device_name
);
3734 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3737 ventoy_set_env(args
[2], name
);
3744 check_free(device_name
, grub_free
);
3745 check_free(dev
, grub_device_close
);
3750 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3760 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3764 for (pos
= args
[0]; *pos
; pos
++)
3778 grub_env_set(args
[1], args
[0]);
3788 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3790 struct grub_video_mode_info info
;
3797 if (!g_video_mode_list
)
3799 ventoy_enum_video_mode();
3802 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3804 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3808 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3811 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3813 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3814 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3816 VENTOY_CMD_RETURN(0);
3819 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3821 struct grub_video_mode_info info
;
3828 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3830 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3834 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3837 grub_env_set(args
[0], buf
);
3839 VENTOY_CMD_RETURN(0);
3842 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3850 if (!g_video_mode_list
)
3855 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3856 if (id
< g_video_mode_num
)
3858 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3859 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3862 grub_env_set(args
[1], buf
);
3864 VENTOY_CMD_RETURN(0);
3867 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3869 grub_uint64_t size
= 0;
3872 char fullpath
[256] = {0};
3875 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3878 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3881 debug("grub_file_open failed <%s>\n", fullpath
);
3887 grub_file_close(file
);
3891 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3895 char fullpath
[256] = {0};
3898 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3901 file
= grub_file_open(fullpath
, type
);
3904 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3911 int ventoy_is_file_exist(const char *fmt
, ...)
3916 char buf
[256] = {0};
3918 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3922 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3925 grub_strncpy(pos
+ len
, "\" ]", 3);
3927 debug("script exec %s\n", buf
);
3929 if (0 == grub_script_execute_sourcecode(buf
))
3937 int ventoy_is_dir_exist(const char *fmt
, ...)
3942 char buf
[256] = {0};
3944 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
3948 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3951 grub_strncpy(pos
+ len
, "\" ]", 3);
3953 debug("script exec %s\n", buf
);
3955 if (0 == grub_script_execute_sourcecode(buf
))
3963 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
3966 grub_uint8_t
*outbuf
;
3967 grub_uint8_t gzHdr
[10] =
3969 0x1F, 0x8B, /* magic */
3972 0,0,0,0, /* mtime */
3977 grub_memset(&s
, 0, sizeof(mz_stream
));
3979 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
3981 outbuf
= (grub_uint8_t
*)mem_out
;
3983 mem_out_len
-= sizeof(gzHdr
) + 8;
3984 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
3985 outbuf
+= sizeof(gzHdr
);
3987 s
.avail_in
= mem_in_len
;
3990 s
.avail_out
= mem_out_len
;
3991 s
.next_out
= outbuf
;
3993 mz_deflate(&s
, MZ_FINISH
);
3997 outbuf
+= s
.total_out
;
3998 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
3999 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
4001 return s
.total_out
+ sizeof(gzHdr
) + 8;
4004 static int ventoy_env_init(void)
4008 grub_env_set("vtdebug_flag", "");
4010 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4011 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4012 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4013 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4015 ventoy_filt_register(0, ventoy_wrapper_open
);
4017 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4020 g_grub_param
->grub_env_get
= grub_env_get
;
4021 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4022 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4023 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4024 grub_env_set("env_param", buf
);
4025 grub_env_set("ventoy_env_param", buf
);
4026 grub_env_export("ventoy_env_param");
4032 static cmd_para ventoy_cmds
[] =
4034 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4035 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4036 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4037 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4038 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4039 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4040 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4041 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4042 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4043 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4044 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4045 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4046 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4047 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4048 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4049 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4050 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4051 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4052 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4053 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4055 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4056 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4057 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4058 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4059 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4060 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4061 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4063 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4064 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4065 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4066 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4067 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4068 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4069 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4070 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4073 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4074 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4075 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4076 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4077 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4078 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4079 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4080 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4081 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4082 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4083 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4085 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4086 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4087 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4088 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4089 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4090 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4092 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4093 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4094 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4095 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4096 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4097 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4098 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4099 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4100 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4101 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4103 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4104 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4105 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4106 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4107 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4108 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4109 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4110 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4112 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4113 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4114 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4117 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4118 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4119 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4121 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4122 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4123 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4126 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4127 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4128 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4129 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4130 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4131 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4132 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4133 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4134 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4135 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4137 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4138 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4139 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4145 GRUB_MOD_INIT(ventoy
)
4148 cmd_para
*cur
= NULL
;
4152 ventoy_arch_mode_init();
4154 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4156 cur
= ventoy_cmds
+ i
;
4157 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4158 cur
->summary
, cur
->description
, cur
->parser
);
4162 GRUB_MOD_FINI(ventoy
)
4166 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4168 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);