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/ventoy.h>
47 #include "ventoy_def.h"
49 GRUB_MOD_LICENSE ("GPLv3+");
51 int g_ventoy_debug
= 0;
52 static int g_efi_os
= 0xFF;
53 initrd_info
*g_initrd_img_list
= NULL
;
54 initrd_info
*g_initrd_img_tail
= NULL
;
55 int g_initrd_img_count
= 0;
56 int g_valid_initrd_count
= 0;
57 int g_default_menu_mode
= 0;
58 int g_filt_dot_underscore_file
= 0;
59 int g_sort_case_sensitive
= 0;
60 int g_tree_view_menu_style
= 0;
61 static grub_file_t g_old_file
;
62 static int g_ventoy_last_entry_back
;
63 static grub_uint32_t g_ventoy_plat_data
;
66 char g_img_swap_tmp_buf
[1024];
67 img_info g_img_swap_tmp
;
68 img_info
*g_ventoy_img_list
= NULL
;
70 int g_ventoy_img_count
= 0;
72 grub_device_t g_enum_dev
= NULL
;
73 grub_fs_t g_enum_fs
= NULL
;
74 img_iterator_node g_img_iterator_head
;
75 img_iterator_node
*g_img_iterator_tail
= NULL
;
77 grub_uint8_t g_ventoy_break_level
= 0;
78 grub_uint8_t g_ventoy_debug_level
= 0;
79 grub_uint8_t g_ventoy_chain_type
= 0;
81 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
82 grub_uint32_t g_ventoy_cpio_size
= 0;
83 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
84 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
86 int g_plugin_image_list
= 0;
88 ventoy_grub_param
*g_grub_param
= NULL
;
90 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
92 ventoy_img_chunk_list g_img_chunk_list
;
94 int g_wimboot_enable
= 0;
95 ventoy_img_chunk_list g_wimiso_chunk_list
;
96 char *g_wimiso_path
= NULL
;
98 int g_vhdboot_enable
= 0;
100 grub_uint64_t g_conf_replace_offset
= 0;
101 grub_uint64_t g_svd_replace_offset
= 0;
102 conf_replace
*g_conf_replace_node
= NULL
;
103 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
104 int g_conf_replace_new_len
= 0;
105 int g_conf_replace_new_len_align
= 0;
107 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
109 static char *g_tree_script_buf
= NULL
;
110 static int g_tree_script_pos
= 0;
112 static char *g_list_script_buf
= NULL
;
113 static int g_list_script_pos
= 0;
115 static char *g_part_list_buf
= NULL
;
116 static int g_part_list_pos
= 0;
118 static int g_video_mode_max
= 0;
119 static int g_video_mode_num
= 0;
120 static ventoy_video_mode
*g_video_mode_list
= NULL
;
122 static const char *g_menu_class
[] =
124 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
127 static const char *g_menu_prefix
[] =
129 "iso", "wim", "efi", "img", "vhd", "vtoy"
132 void ventoy_debug(const char *fmt
, ...)
136 va_start (args
, fmt
);
137 grub_vprintf (fmt
, args
);
141 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
151 for (i
= 0; i
< 16; i
++)
153 grub_printf("%02x ", guid
[i
]);
158 int ventoy_is_efi_os(void)
162 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
168 static int ventoy_get_fs_type(const char *fs
)
172 return ventoy_fs_max
;
174 else if (grub_strncmp(fs
, "exfat", 5) == 0)
176 return ventoy_fs_exfat
;
178 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
180 return ventoy_fs_ntfs
;
182 else if (grub_strncmp(fs
, "ext", 3) == 0)
184 return ventoy_fs_ext
;
186 else if (grub_strncmp(fs
, "xfs", 3) == 0)
188 return ventoy_fs_xfs
;
190 else if (grub_strncmp(fs
, "udf", 3) == 0)
192 return ventoy_fs_udf
;
194 else if (grub_strncmp(fs
, "fat", 3) == 0)
196 return ventoy_fs_fat
;
199 return ventoy_fs_max
;
202 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
221 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
223 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
227 static grub_err_t
ventoy_fs_close(grub_file_t file
)
229 grub_file_close(g_old_file
);
230 grub_free(file
->data
);
238 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
244 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
249 for (i
= 0; i
< g_video_mode_num
; i
++)
251 if (g_video_mode_list
[i
].width
== info
->width
&&
252 g_video_mode_list
[i
].height
== info
->height
&&
253 g_video_mode_list
[i
].bpp
== info
->bpp
)
259 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
260 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
261 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
264 if (g_video_mode_num
== g_video_mode_max
)
266 g_video_mode_max
*= 2;
267 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
273 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
275 if (v1
->bpp
== v2
->bpp
)
277 if (v1
->width
== v2
->width
)
279 if (v1
->height
== v2
->height
)
285 return (v1
->height
< v2
->height
) ? -1 : 1;
290 return (v1
->width
< v2
->width
) ? -1 : 1;
295 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
299 static int ventoy_enum_video_mode(void)
302 grub_video_adapter_t adapter
;
303 grub_video_driver_id_t id
;
304 ventoy_video_mode mode
;
306 g_video_mode_num
= 0;
307 g_video_mode_max
= 1024;
308 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
309 if (!g_video_mode_list
)
314 #ifdef GRUB_MACHINE_PCBIOS
315 grub_dl_load ("vbe");
318 id
= grub_video_get_driver_id ();
320 FOR_VIDEO_ADAPTERS (adapter
)
322 if (!adapter
->iterate
||
323 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
324 adapter
->init() != GRUB_ERR_NONE
)))
329 adapter
->iterate(ventoy_video_hook
, NULL
);
331 if (adapter
->id
!= id
)
337 /* sort video mode */
338 for (i
= 0; i
< g_video_mode_num
; i
++)
339 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
341 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
343 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
344 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
345 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
349 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
352 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
356 static struct grub_fs vtoy_fs
=
361 .fs_read
= ventoy_fs_read
,
362 .fs_close
= ventoy_fs_close
,
372 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
378 file
->data
= grub_malloc(rawFile
->size
+ 4096);
384 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
385 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
387 g_old_file
= rawFile
;
389 file
->size
= rawFile
->size
+ len
;
390 file
->device
= rawFile
->device
;
392 file
->not_easily_seekable
= 1;
397 static int ventoy_check_decimal_var(const char *name
, long *value
)
399 const char *value_str
= NULL
;
401 value_str
= grub_env_get(name
);
402 if (NULL
== value_str
)
404 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
407 if (!ventoy_is_decimal(value_str
))
409 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
412 *value
= grub_strtol(value_str
, NULL
, 10);
414 return GRUB_ERR_NONE
;
417 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
421 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
424 if (0 == grub_strcmp(args
[0], "on"))
427 grub_env_set("vtdebug_flag", "debug");
432 grub_env_set("vtdebug_flag", "");
435 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
438 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
442 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
444 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
445 grub_printf(" level:\r\n");
446 grub_printf(" 01/11: busybox / (+cat log)\r\n");
447 grub_printf(" 02/12: initrd / (+cat log)\r\n");
448 grub_printf(" 03/13: hook / (+cat log)\r\n");
450 grub_printf(" debug:\r\n");
451 grub_printf(" 0: debug is off\r\n");
452 grub_printf(" 1: debug is on\r\n");
454 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
457 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
459 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
461 g_ventoy_debug_level
= 1;
464 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
467 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
476 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
479 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
511 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
516 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
518 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
521 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
526 value_long
+= grub_strtol(args
[1], NULL
, 10);
528 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
529 grub_env_set(args
[0], buf
);
531 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
534 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
549 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
552 debug("failed to open file <%s> for udf check\n", args
[0]);
556 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
558 grub_env_set(args
[1], buf
);
560 grub_file_close(file
);
566 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
574 g_wimboot_enable
= 0;
575 grub_check_free(g_wimiso_path
);
576 grub_check_free(g_wimiso_chunk_list
.chunk
);
578 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
584 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
585 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
586 if (NULL
== g_wimiso_chunk_list
.chunk
)
588 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
591 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
592 g_wimiso_chunk_list
.cur_chunk
= 0;
594 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
596 g_wimboot_enable
= 1;
597 g_wimiso_path
= grub_strdup(args
[0]);
599 grub_file_close(file
);
604 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
610 grub_uint32_t offset
;
612 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
615 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
619 len
= (int)file
->size
;
621 data
= (char *)grub_malloc(file
->size
);
627 grub_file_read(file
, data
, file
->size
);
628 grub_file_close(file
);
630 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
631 grub_script_execute_sourcecode(exec
);
633 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
634 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
635 grub_file_close(file
);
637 grub_script_execute_sourcecode("loopback -d efiboot");
641 *direntoff
= offset
+ 2;
646 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
656 ventoy_iso9660_override
*dirent
;
665 totlen
= sizeof(ventoy_chain_head
);
667 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
669 debug("failed to load efiboot template %d\n", len
);
675 debug("efiboot template len:%d offset:%d\n", len
, offset
);
677 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
680 debug("failed to open file <%s>\n", args
[0]);
684 totlen
+= ventoy_align_2k(file
->size
);
686 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
687 dirent
->first_sector
= len
/ 2048;
688 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
689 dirent
->size
= (grub_uint32_t
)file
->size
;
690 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
692 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
694 #ifdef GRUB_MACHINE_EFI
695 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
697 data
= (char *)grub_malloc(totlen
);
700 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
702 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
703 grub_check_free(buf
);
705 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
706 grub_file_close(file
);
708 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
709 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
710 grub_env_set(name
, value
);
712 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
713 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
714 grub_env_set(name
, value
);
719 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
736 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
739 debug("failed to open file <%s>\n", args
[0]);
743 #ifdef GRUB_MACHINE_EFI
744 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
746 buf
= (char *)grub_malloc(file
->size
);
749 grub_file_read(file
, buf
, file
->size
);
751 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
752 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
753 grub_env_set(name
, value
);
755 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
756 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
757 grub_env_set(name
, value
);
759 grub_file_close(file
);
765 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
783 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
786 debug("failed to open file <%s> for udf check\n", args
[0]);
790 headlen
= sizeof(ventoy_chain_head
);
792 #ifdef GRUB_MACHINE_EFI
793 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
795 buf
= (char *)grub_malloc(headlen
+ file
->size
);
798 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
800 grub_file_read(file
, buf
+ headlen
, file
->size
);
802 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
803 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
804 grub_env_set(name
, value
);
806 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
807 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
808 grub_env_set(name
, value
);
810 grub_file_close(file
);
816 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
825 if (args
[0][0] == '1')
827 grub_iso9660_set_nojoliet(1);
831 grub_iso9660_set_nojoliet(0);
837 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
842 grub_uint8_t buf
[32];
853 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
856 debug("failed to open file <%s> for udf check\n", args
[0]);
860 for (i
= 16; i
< 32; i
++)
862 grub_file_seek(file
, i
* 2048);
863 grub_file_read(file
, buf
, sizeof(buf
));
871 grub_file_seek(file
, i
* 2048);
872 grub_file_read(file
, buf
, sizeof(buf
));
874 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
877 grub_file_seek(file
, i
* 2048);
878 grub_file_read(file
, buf
, sizeof(buf
));
880 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
881 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
887 grub_file_close(file
);
889 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
894 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
896 long value_long1
= 0;
897 long value_long2
= 0;
899 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
901 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
904 value_long1
= grub_strtol(args
[0], NULL
, 10);
905 value_long2
= grub_strtol(args
[2], NULL
, 10);
907 if (0 == grub_strcmp(args
[1], "eq"))
909 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
911 else if (0 == grub_strcmp(args
[1], "ne"))
913 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
915 else if (0 == grub_strcmp(args
[1], "gt"))
917 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
919 else if (0 == grub_strcmp(args
[1], "lt"))
921 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
923 else if (0 == grub_strcmp(args
[1], "ge"))
925 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
927 else if (0 == grub_strcmp(args
[1], "le"))
929 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
933 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
939 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
946 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
949 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
950 pos
= grub_strstr(buf
, ",");
956 grub_env_set(args
[1], buf
);
958 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
961 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
967 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
973 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
976 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
978 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
979 if (0 == grub_script_execute_sourcecode(buf
))
981 debug("file %s exist, ventoy_compatible YES\n", buf
);
982 grub_env_set("ventoy_compatible", "YES");
983 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
987 debug("file %s NOT exist\n", buf
);
991 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
992 pos
= grub_strstr(buf
, ")");
998 disk
= grub_disk_open(buf
);
1001 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1002 grub_disk_close(disk
);
1004 g_img_swap_tmp_buf
[703] = 0;
1005 for (i
= 318; i
< 703; i
++)
1007 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1008 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1010 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1011 grub_env_set("ventoy_compatible", "YES");
1012 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1018 debug("failed to open disk <%s>\n", buf
);
1021 grub_env_set("ventoy_compatible", "NO");
1022 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1025 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1031 if (g_plugin_image_list
)
1033 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1036 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1041 if (0 == g_sort_case_sensitive
)
1043 if (grub_islower(c1
))
1045 c1
= c1
- 'a' + 'A';
1048 if (grub_islower(c2
))
1050 c2
= c2
- 'a' + 'A';
1063 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1069 if (g_plugin_image_list
)
1071 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1074 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1079 if (0 == g_sort_case_sensitive
)
1081 if (grub_islower(c1
))
1083 c1
= c1
- 'a' + 'A';
1086 if (grub_islower(c2
))
1088 c2
= c2
- 'a' + 'A';
1101 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1103 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1105 grub_memcpy(img1
, img2
, sizeof(img_info
));
1106 img1
->next
= g_img_swap_tmp
.next
;
1107 img1
->prev
= g_img_swap_tmp
.prev
;
1109 g_img_swap_tmp
.next
= img2
->next
;
1110 g_img_swap_tmp
.prev
= img2
->prev
;
1111 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1114 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1118 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1126 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1130 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1140 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1149 img_iterator_node
*tmp
;
1150 img_iterator_node
*new_node
;
1151 img_iterator_node
*node
= (img_iterator_node
*)data
;
1153 len
= grub_strlen(filename
);
1157 if ((len
== 1 && filename
[0] == '.') ||
1158 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1163 if (!ventoy_img_name_valid(filename
, len
))
1168 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1173 if (g_plugin_image_list
)
1175 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1176 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1179 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1184 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1187 new_node
->plugin_list_index
= index
;
1188 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1190 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1193 debug("Directory %s ignored...\n", new_node
->dir
);
1194 grub_free(new_node
);
1198 new_node
->tail
= node
->tail
;
1200 new_node
->parent
= node
;
1201 if (!node
->firstchild
)
1203 node
->firstchild
= new_node
;
1206 if (g_img_iterator_tail
)
1208 g_img_iterator_tail
->next
= new_node
;
1209 g_img_iterator_tail
= new_node
;
1213 g_img_iterator_head
.next
= new_node
;
1214 g_img_iterator_tail
= new_node
;
1220 debug("Find a file %s\n", filename
);
1226 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1228 type
= img_type_iso
;
1230 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1232 type
= img_type_wim
;
1234 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1235 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1237 type
= img_type_vhd
;
1239 #ifdef GRUB_MACHINE_EFI
1240 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1242 type
= img_type_efi
;
1245 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1247 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1249 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1250 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1255 type
= img_type_img
;
1257 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1259 type
= img_type_vtoy
;
1266 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1271 if (g_plugin_image_list
)
1273 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1274 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1277 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1282 img
= grub_zalloc(sizeof(img_info
));
1286 img
->plugin_list_index
= index
;
1287 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1289 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1291 img
->size
= info
->size
;
1294 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1297 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1299 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1304 if (g_ventoy_img_list
)
1306 tail
= *(node
->tail
);
1312 g_ventoy_img_list
= img
;
1315 img
->id
= g_ventoy_img_count
;
1317 if (node
&& NULL
== node
->firstiso
)
1319 node
->firstiso
= img
;
1330 *((img_info
**)(node
->tail
)) = img
;
1331 g_ventoy_img_count
++;
1333 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1334 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1337 img
->class = g_menu_class
[type
];
1339 img
->menu_prefix
= g_menu_prefix
[type
];
1341 if (img_type_iso
== type
)
1343 if (ventoy_plugin_check_memdisk(img
->path
))
1345 img
->menu_prefix
= "miso";
1349 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1356 static int ventoy_arch_mode_init(void)
1358 #ifdef GRUB_MACHINE_EFI
1359 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1361 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1362 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1364 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1366 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1367 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1371 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1372 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1375 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1376 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1382 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1384 int len
= GRUB_UINT_MAX
;
1385 const char *value
= NULL
;
1386 char name
[32] = {0};
1387 char plat
[32] = {0};
1388 char guidstr
[32] = {0};
1389 ventoy_guid guid
= VENTOY_GUID
;
1390 const char *fmt1
= NULL
;
1391 const char *fmt2
= NULL
;
1392 const char *fmt3
= NULL
;
1393 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1394 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1395 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1396 const char fmtcode
[]={
1397 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1398 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1399 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1400 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1401 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1402 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1405 grub_memset(name
, 0, sizeof(name
));
1406 puint
[0] = grub_swap_bytes32(0x56454e54);
1407 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1408 puint
[2] = grub_swap_bytes32(0x45525349);
1409 puint
[1] = grub_swap_bytes32(0x4f595f56);
1410 value
= ventoy_get_env(name
);
1412 grub_memset(name
, 0, sizeof(name
));
1413 puint
[1] = grub_swap_bytes32(0x5f544f50);
1414 puint
[0] = grub_swap_bytes32(0x56544c45);
1415 fmt1
= ventoy_get_env(name
);
1421 grub_memset(name
, 0, sizeof(name
));
1422 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1423 puint
[0] = grub_swap_bytes32(0x56544c45);
1424 fmt2
= ventoy_get_env(name
);
1426 grub_memset(name
, 0, sizeof(name
));
1427 puint
[1] = grub_swap_bytes32(0x5f434c52);
1428 puint
[0] = grub_swap_bytes32(0x56544c45);
1429 fmt3
= ventoy_get_env(name
);
1431 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1433 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1435 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1436 #pragma GCC diagnostic push
1437 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1438 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1439 fmt1
? fmt1
: fmtdata
,
1440 fmt2
? fmt2
: fmtdata
+ 4,
1441 value
? value
: "", plat
, guidstr
,
1442 fmt3
? fmt3
: fmtdata
+ 6);
1443 #pragma GCC diagnostic pop
1445 grub_memset(name
, 0, sizeof(name
));
1446 puint
[0] = grub_swap_bytes32(0x76746f79);
1447 puint
[2] = grub_swap_bytes32(0x656e7365);
1448 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1449 ventoy_set_env(name
, guidstr
);
1454 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1458 grub_uint8_t md5
[16];
1462 grub_memset(input
, 0, sizeof(input
));
1464 grub_printf("Enter password: ");
1467 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1469 grub_password_get(input
, 128);
1470 if (grub_strcmp(pwd
->text
, input
) == 0)
1475 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1477 grub_password_get(input
, 128);
1478 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1479 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1484 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1486 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1487 grub_password_get(input
+ offset
, 128);
1489 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1490 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1496 grub_printf("Invalid password!\n\n");
1503 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1505 img_info
*minimg
= NULL
;
1506 img_info
*img
= (img_info
*)(node
->firstiso
);
1508 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1510 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1525 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1527 img_iterator_node
*Minchild
= NULL
;
1528 img_iterator_node
*child
= node
->firstchild
;
1530 while (child
&& child
->parent
== node
)
1532 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1536 child
= child
->next
;
1541 Minchild
->select
= 1;
1547 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1550 img_info
*img
= NULL
;
1551 const char *dir_class
= NULL
;
1552 const char *dir_alias
= NULL
;
1553 img_iterator_node
*child
= NULL
;
1555 if (node
->isocnt
== 0 || node
->done
== 1)
1560 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1562 offset
= node
->parent
->dirlen
;
1565 if (node
== &g_img_iterator_head
)
1567 if (g_default_menu_mode
== 0)
1569 if (g_tree_view_menu_style
== 0)
1571 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1572 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1573 " echo 'return ...' \n"
1578 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1579 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1587 node
->dir
[node
->dirlen
- 1] = 0;
1588 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1591 dir_class
= "vtoydir";
1594 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1597 if (g_tree_view_menu_style
== 0)
1599 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1600 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1601 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1605 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1606 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1607 dir_alias
, dir_class
, node
->dir
+ offset
);
1612 dir_alias
= node
->dir
+ offset
;
1614 if (g_tree_view_menu_style
== 0)
1616 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1617 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1618 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1622 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1623 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1624 dir_alias
, dir_class
, node
->dir
+ offset
);
1628 if (g_tree_view_menu_style
== 0)
1630 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1631 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1632 " echo 'return ...' \n"
1637 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1638 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1644 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1646 ventoy_dynamic_tree_menu(child
);
1649 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1651 if (g_tree_view_menu_style
== 0)
1653 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1654 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1657 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1658 img
->unsupport
? "[***********] " : "",
1659 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1661 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1665 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1666 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1669 img
->unsupport
? "[***********] " : "",
1670 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1672 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1676 if (node
!= &g_img_iterator_head
)
1678 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1685 int ventoy_check_device_result(int ret
)
1689 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1690 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1691 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1695 grub_printf(VTOY_WARNING
"\n");
1696 grub_printf(VTOY_WARNING
"\n");
1697 grub_printf(VTOY_WARNING
"\n\n\n");
1699 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1700 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1702 grub_printf("\n\nWill exit after 10 seconds ...... ");
1710 int ventoy_check_device(grub_device_t dev
)
1713 grub_uint64_t offset
;
1718 struct grub_partition
*partition
;
1720 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1722 return ventoy_check_device_result(1 | 0x1000);
1725 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1726 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1727 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1729 return ventoy_check_device_result(2 | 0x1000);
1732 /* We must have partition 2 */
1733 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1736 return ventoy_check_device_result(3 | 0x1000);
1739 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1741 grub_file_close(file
);
1742 return ventoy_check_device_result(4 | 0x1000);
1745 partition
= dev
->disk
->partition
;
1746 if (partition
->number
!= 0 || partition
->start
!= 2048)
1748 return ventoy_check_device_result(5);
1751 offset
= partition
->start
+ partition
->len
;
1752 partition
= file
->device
->disk
->partition
;
1753 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1755 grub_file_close(file
);
1756 return ventoy_check_device_result(6);
1758 grub_file_close(file
);
1760 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1761 dev2
= grub_device_open(devname
);
1764 return ventoy_check_device_result(7);
1767 fs
= grub_fs_probe(dev2
);
1770 grub_device_close(dev2
);
1771 return ventoy_check_device_result(8);
1774 fs
->fs_label(dev2
, &label
);
1775 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1777 grub_device_close(dev2
);
1778 return ventoy_check_device_result(9);
1781 grub_device_close(dev2
);
1782 return ventoy_check_device_result(0);
1785 static int ventoy_set_default_menu(void)
1791 const char *strdata
= NULL
;
1792 img_info
*cur
= NULL
;
1793 img_info
*default_node
= NULL
;
1794 const char *default_image
= NULL
;
1796 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1797 if (default_image
&& default_image
[0] == '/')
1799 img_len
= grub_strlen(default_image
);
1801 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1803 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1815 if (0 == g_default_menu_mode
)
1817 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1821 def
= grub_strdup(default_image
);
1827 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1829 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1830 if (strdata
&& strdata
[0] == '/')
1832 pos
= def
+ grub_strlen(strdata
);
1843 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1846 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1850 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1858 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1862 grub_device_t dev
= NULL
;
1863 img_info
*cur
= NULL
;
1864 img_info
*tail
= NULL
;
1865 const char *strdata
= NULL
;
1866 char *device_name
= NULL
;
1868 img_iterator_node
*node
= NULL
;
1869 img_iterator_node
*tmp
= NULL
;
1875 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1878 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1880 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1883 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1884 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1886 g_filt_dot_underscore_file
= 1;
1889 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1890 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1892 g_sort_case_sensitive
= 1;
1895 device_name
= grub_file_get_device_name(args
[0]);
1901 g_enum_dev
= dev
= grub_device_open(device_name
);
1907 g_enum_fs
= fs
= grub_fs_probe(dev
);
1913 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1915 debug("unsupported fs:<%s>\n", fs
->name
);
1916 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1920 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1922 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1923 if (strdata
&& strdata
[0] == '1')
1925 g_default_menu_mode
= 1;
1928 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1930 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1932 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1933 if (strdata
&& strdata
[0] == '/')
1935 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1936 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1938 g_img_iterator_head
.dir
[len
++] = '/';
1940 g_img_iterator_head
.dirlen
= len
;
1944 g_img_iterator_head
.dirlen
= 1;
1945 grub_strcpy(g_img_iterator_head
.dir
, "/");
1948 g_img_iterator_head
.tail
= &tail
;
1950 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1952 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1955 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1956 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1958 g_tree_view_menu_style
= 1;
1961 ventoy_set_default_menu();
1963 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1965 ventoy_dynamic_tree_menu(node
);
1969 node
= g_img_iterator_head
.next
;
1977 /* sort image list by image name */
1978 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1980 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1982 if (ventoy_cmp_img(cur
, tail
) > 0)
1984 ventoy_swap_img(cur
, tail
);
1989 if (g_default_menu_mode
== 1)
1991 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1992 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1993 " echo 'return ...' \n"
1997 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1999 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2000 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2003 cur
->unsupport
? "[***********] " : "",
2004 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2006 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2009 g_tree_script_buf
[g_tree_script_pos
] = 0;
2010 g_list_script_buf
[g_list_script_pos
] = 0;
2012 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2013 grub_env_set(args
[1], buf
);
2017 check_free(device_name
, grub_free
);
2018 check_free(dev
, grub_device_close
);
2020 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2024 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2026 img_info
*next
= NULL
;
2027 img_info
*cur
= g_ventoy_img_list
;
2040 g_ventoy_img_list
= NULL
;
2041 g_ventoy_img_count
= 0;
2043 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2046 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2049 img_info
*cur
= g_ventoy_img_list
;
2053 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2055 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2058 img_id
= grub_strtol(args
[0], NULL
, 10);
2059 if (img_id
>= g_ventoy_img_count
)
2061 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2064 debug("Find image %ld name \n", img_id
);
2066 while (cur
&& img_id
> 0)
2074 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2077 debug("image name is %s\n", cur
->name
);
2079 grub_env_set(args
[1], cur
->name
);
2081 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2084 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2089 const char *id
= NULL
;
2090 img_info
*cur
= g_ventoy_img_list
;
2094 if (argc
< 1 || argc
> 2)
2096 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2099 id
= grub_env_get("chosen");
2101 pos
= grub_strstr(id
, "VID_");
2104 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2108 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2113 if (img_id
== cur
->id
)
2122 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2125 grub_env_set(args
[0], cur
->path
);
2129 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2130 grub_env_set(args
[1], value
);
2133 g_svd_replace_offset
= 0;
2135 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2138 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2145 device_name
= grub_file_get_device_name(filename
);
2157 pos2
= grub_strstr(pos
, ",");
2160 pos2
= grub_strstr(pos
, ")");
2168 disk
= grub_disk_open(pos
);
2171 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2172 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2173 grub_disk_close(disk
);
2180 grub_free(device_name
);
2184 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2186 eltorito_descriptor desc
;
2188 grub_memset(&desc
, 0, sizeof(desc
));
2189 grub_file_seek(file
, 17 * 2048);
2190 grub_file_read(file
, &desc
, sizeof(desc
));
2192 if (desc
.type
!= 0 || desc
.version
!= 1)
2197 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2198 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2206 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2210 grub_uint8_t buf
[512];
2212 grub_file_seek(file
, sector
* 2048);
2213 grub_file_read(file
, buf
, sizeof(buf
));
2215 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2217 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2221 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2226 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2228 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2230 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2234 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2236 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2241 debug("%s does not contain efi eltorito\n", file
->name
);
2245 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2248 const char *fs
= NULL
;
2249 const char *cdprompt
= NULL
;
2251 grub_uint8_t chksum
= 0;
2254 disk
= file
->device
->disk
;
2255 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2257 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2258 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2259 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2261 pos
= grub_strstr(file
->name
, "/");
2267 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2269 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2271 param
->vtoy_img_size
= file
->size
;
2273 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2274 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2276 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2278 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2279 param
->vtoy_reserved
[4] = 0;
2280 if (g_ventoy_chain_type
== 1) /* Windows */
2282 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2283 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2285 param
->vtoy_reserved
[4] = 1;
2289 fs
= ventoy_get_env("ventoy_fs_probe");
2290 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2292 param
->vtoy_reserved
[3] = 1;
2295 /* calculate checksum */
2296 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2298 chksum
+= *((grub_uint8_t
*)param
+ i
);
2300 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2305 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2307 grub_uint32_t i
= 0;
2308 grub_uint64_t total
= 0;
2309 ventoy_img_chunk
*chunk
= NULL
;
2311 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2313 chunk
= chunklist
->chunk
+ i
;
2315 if (chunk
->disk_start_sector
<= start
)
2317 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2321 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2324 if (total
!= ((file
->size
+ 511) / 512))
2326 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2333 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2337 grub_uint32_t i
= 0;
2338 grub_uint32_t sector
= 0;
2339 grub_uint32_t count
= 0;
2340 grub_off_t size
= 0;
2341 grub_off_t read
= 0;
2343 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2344 if (fs_type
== ventoy_fs_exfat
)
2346 grub_fat_get_file_chunk(start
, file
, chunklist
);
2348 else if (fs_type
== ventoy_fs_ext
)
2350 grub_ext_get_file_chunk(start
, file
, chunklist
);
2354 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2355 file
->read_hook_data
= chunklist
;
2357 for (size
= file
->size
; size
> 0; size
-= read
)
2359 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2360 grub_file_read(file
, NULL
, read
);
2363 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2365 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2366 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2369 if (ventoy_fs_udf
== fs_type
)
2371 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2373 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2374 chunklist
->chunk
[i
].img_start_sector
= sector
;
2375 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2381 len
= (int)grub_strlen(file
->name
);
2382 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2383 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2384 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2385 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2387 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2389 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2399 chunklist
->chunk
[i
].img_start_sector
= sector
;
2400 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2408 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2412 grub_disk_addr_t start
;
2417 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2420 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2423 g_conf_replace_node
= NULL
;
2424 g_conf_replace_offset
= 0;
2426 if (g_img_chunk_list
.chunk
)
2428 grub_free(g_img_chunk_list
.chunk
);
2431 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2433 grub_file_close(file
);
2434 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2437 /* get image chunk data */
2438 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2439 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2440 if (NULL
== g_img_chunk_list
.chunk
)
2442 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2445 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2446 g_img_chunk_list
.cur_chunk
= 0;
2448 start
= file
->device
->disk
->partition
->start
;
2450 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2452 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2453 grub_file_close(file
);
2457 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2460 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2461 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2464 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2466 grub_uint64_t offset
= 0;
2467 grub_uint32_t align
= 0;
2468 grub_file_t file
= NULL
;
2469 conf_replace
*node
= NULL
;
2475 debug("select conf replace argc:%d\n", argc
);
2482 node
= ventoy_plugin_find_conf_replace(args
[1]);
2485 debug("Conf replace not found for %s\n", args
[1]);
2489 debug("Find conf replace for %s\n", args
[1]);
2491 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2494 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2498 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2499 grub_file_close(file
);
2501 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2504 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2508 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2510 if (align
> vtoy_max_replace_file_size
)
2512 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2516 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2517 g_conf_replace_new_len
= (int)file
->size
;
2518 g_conf_replace_new_len_align
= align
;
2520 g_conf_replace_node
= node
;
2521 g_conf_replace_offset
= offset
+ 2;
2523 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2528 grub_file_close(file
);
2530 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2533 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2538 char configfile
[128];
2539 install_template
*node
= NULL
;
2545 debug("select auto installation argc:%d\n", argc
);
2552 node
= ventoy_plugin_find_install_template(args
[0]);
2555 debug("Auto install template not found for %s\n", args
[0]);
2559 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2561 node
->cursel
= node
->autosel
- 1;
2562 debug("Auto install template auto select %d\n", node
->autosel
);
2566 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2572 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2573 " echo %s\n}\n", "123");
2575 for (i
= 0; i
< node
->templatenum
; i
++)
2577 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2579 node
->templatepath
[i
].path
);
2582 g_ventoy_menu_esc
= 1;
2583 g_ventoy_suppress_esc
= 1;
2585 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2586 grub_script_execute_sourcecode(configfile
);
2588 g_ventoy_menu_esc
= 0;
2589 g_ventoy_suppress_esc
= 0;
2593 node
->cursel
= g_ventoy_last_entry
- 1;
2595 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2598 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2603 char configfile
[128];
2604 persistence_config
*node
;
2610 debug("select persistence argc:%d\n", argc
);
2617 node
= ventoy_plugin_find_persistent(args
[0]);
2620 debug("Persistence image not found for %s\n", args
[0]);
2624 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2626 node
->cursel
= node
->autosel
- 1;
2627 debug("Persistence image auto select %d\n", node
->autosel
);
2631 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2637 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2638 " echo %s\n}\n", "123");
2640 for (i
= 0; i
< node
->backendnum
; i
++)
2642 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2644 node
->backendpath
[i
].path
);
2648 g_ventoy_menu_esc
= 1;
2649 g_ventoy_suppress_esc
= 1;
2651 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2652 grub_script_execute_sourcecode(configfile
);
2654 g_ventoy_menu_esc
= 0;
2655 g_ventoy_suppress_esc
= 0;
2659 node
->cursel
= g_ventoy_last_entry
- 1;
2661 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2664 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2667 ventoy_img_chunk
*cur
;
2673 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2675 cur
= g_img_chunk_list
.chunk
+ i
;
2676 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2677 cur
->img_start_sector
, cur
->img_end_sector
,
2678 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2682 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2685 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2689 ventoy_img_chunk_list chunklist
;
2694 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2697 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2700 /* get image chunk data */
2701 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2702 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2703 if (NULL
== chunklist
.chunk
)
2705 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2708 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2709 chunklist
.cur_chunk
= 0;
2711 ventoy_get_block_list(file
, &chunklist
, 0);
2713 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2715 grub_printf("########## UNSUPPORTED ###############\n");
2718 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2720 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2722 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2723 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2726 grub_printf("\n==================================\n");
2728 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2730 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2731 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2732 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2733 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2734 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2738 grub_free(chunklist
.chunk
);
2739 grub_file_close(file
);
2741 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2744 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2747 ventoy_grub_param_file_replace
*replace
= NULL
;
2755 replace
= &(g_grub_param
->file_replace
);
2756 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2758 replace
->old_name_cnt
= 0;
2759 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2761 replace
->old_name_cnt
++;
2762 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2765 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2768 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2771 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2779 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2780 grub_printf("%s", g_list_script_buf
);
2784 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2785 grub_printf("%s", g_tree_script_buf
);
2791 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2793 img_info
*cur
= g_ventoy_img_list
;
2801 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2802 grub_printf("name:<%s>\n\n", cur
->name
);
2809 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2815 ventoy_plugin_dump_injection();
2820 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2826 ventoy_plugin_dump_auto_install();
2831 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2837 ventoy_plugin_dump_persistence();
2842 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2853 if (args
[0][0] == '0')
2855 return g_ventoy_memdisk_mode
? 0 : 1;
2857 else if (args
[0][0] == '1')
2859 return g_ventoy_iso_raw
? 0 : 1;
2861 else if (args
[0][0] == '2')
2863 return g_ventoy_iso_uefi_drv
? 0 : 1;
2869 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2871 static int configfile_mode
= 0;
2872 char memfile
[128] = {0};
2879 * args[0]: 0:normal 1:configfile
2880 * args[1]: 0:list_buf 1:tree_buf
2885 debug("Invalid argc %d\n", argc
);
2889 if (args
[0][0] == '0')
2891 if (args
[1][0] == '0')
2893 grub_script_execute_sourcecode(g_list_script_buf
);
2897 grub_script_execute_sourcecode(g_tree_script_buf
);
2902 if (configfile_mode
)
2904 debug("Now already in F3 mode %d\n", configfile_mode
);
2908 if (args
[1][0] == '0')
2910 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2911 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2915 g_ventoy_last_entry
= -1;
2916 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2917 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2920 configfile_mode
= 1;
2921 grub_script_execute_sourcecode(memfile
);
2922 configfile_mode
= 0;
2928 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2939 g_ventoy_case_insensitive
= 1;
2940 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2941 g_ventoy_case_insensitive
= 0;
2947 grub_file_close(file
);
2953 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2958 const char *isopath
= NULL
;
2960 ventoy_mbr_head mbr
;
2967 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2970 isopath
= grub_env_get("vtoy_iso_part");
2973 debug("isopath is null %p\n", isopath
);
2977 debug("isopath is %s\n", isopath
);
2979 for (id
= 0; id
< 30 && (find
== 0); id
++)
2981 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2982 if (grub_strstr(isopath
, hdname
))
2984 debug("skip %s ...\n", hdname
);
2988 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2990 disk
= grub_disk_open(hdname
);
2993 debug("%s not exist\n", hdname
);
2997 grub_memset(&mbr
, 0, sizeof(mbr
));
2998 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3000 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3002 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3003 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3006 grub_env_set(args
[0], hdname
);
3010 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3014 debug("read %s failed\n", hdname
);
3017 grub_disk_close(disk
);
3023 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3034 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3037 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3040 debug("failed to open file %s\n", args
[0]);
3044 buf
= grub_malloc(len
);
3051 grub_file_read(file
, buf
, len
- 1);
3053 ventoy_get_line(buf
);
3054 ventoy_set_env(args
[1], buf
);
3058 grub_check_free(buf
);
3059 grub_file_close(file
);
3064 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3069 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3070 "0 %llu linear /dev/ventoy %llu\n",
3071 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3076 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3078 char *device_name
= NULL
;
3079 grub_device_t dev
= NULL
;
3084 g_part_list_pos
= 0;
3085 grub_env_unset("vtoy_img_part_file");
3092 device_name
= grub_file_get_device_name(args
[0]);
3095 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3099 dev
= grub_device_open(device_name
);
3102 debug("grub_device_open failed, %s\n", device_name
);
3106 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3108 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3109 grub_env_set("vtoy_img_part_file", buf
);
3113 check_free(device_name
, grub_free
);
3114 check_free(dev
, grub_device_close
);
3120 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3131 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3134 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3137 debug("failed to open file %s\n", args
[0]);
3141 buf
= grub_malloc(file
->size
+ 1);
3147 buf
[file
->size
] = 0;
3148 grub_file_read(file
, buf
, file
->size
);
3150 if (grub_strstr(buf
, args
[1]))
3157 grub_check_free(buf
);
3158 grub_file_close(file
);
3163 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3168 ventoy_iso9660_vd pvd
;
3175 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3178 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3181 debug("failed to open file %s\n", args
[0]);
3185 grub_file_seek(file
, 16 * 2048);
3186 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3187 if (len
!= sizeof(pvd
))
3189 debug("failed to read pvd %d\n", len
);
3193 grub_memset(buf
, 0, sizeof(buf
));
3194 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3195 ventoy_set_env(args
[1], buf
);
3197 grub_memset(buf
, 0, sizeof(buf
));
3198 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3199 ventoy_set_env(args
[2], buf
);
3202 grub_file_close(file
);
3207 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3218 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3221 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3224 debug("failed to open file %s\n", args
[0]);
3228 grub_memset(buf
, 0, sizeof(buf
));
3229 grub_file_seek(file
, 16 * 2048 + 813);
3230 len
= (int)grub_file_read(file
, buf
, 17);
3233 debug("failed to read create date %d\n", len
);
3237 ventoy_set_env(args
[1], buf
);
3240 grub_file_close(file
);
3245 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3251 ventoy_env_hook_root(1);
3256 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3262 ventoy_env_hook_root(0);
3267 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3274 int image_sector_size
;
3276 ventoy_chain_head
*chain
;
3277 ventoy_img_chunk
*chunk
;
3278 ventoy_os_param
*osparam
;
3279 ventoy_image_location
*location
;
3280 ventoy_image_disk_region
*region
;
3281 struct grub_acpi_table_header
*acpi
;
3290 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3292 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3298 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3300 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3302 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3306 img_chunk_num
= chain
->img_chunk_num
;
3308 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3309 datalen
= sizeof(ventoy_os_param
) + loclen
;
3311 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3312 acpi
= grub_zalloc(buflen
);
3318 /* Step1: Fill acpi table header */
3319 grub_memcpy(acpi
->signature
, "VTOY", 4);
3320 acpi
->length
= buflen
;
3322 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3323 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3325 acpi
->creator_id
[0] = 1;
3326 acpi
->creator_rev
= 1;
3328 /* Step2: Fill data */
3329 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3330 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3331 osparam
->vtoy_img_location_addr
= 0;
3332 osparam
->vtoy_img_location_len
= loclen
;
3333 osparam
->chksum
= 0;
3334 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3336 location
= (ventoy_image_location
*)(osparam
+ 1);
3337 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3338 location
->image_sector_size
= image_sector_size
;
3339 location
->disk_sector_size
= chain
->disk_sector_size
;
3340 location
->region_count
= img_chunk_num
;
3342 region
= location
->regions
;
3343 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3344 if (512 == image_sector_size
)
3346 for (i
= 0; i
< img_chunk_num
; i
++)
3348 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3349 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3350 region
->disk_start_sector
= chunk
->disk_start_sector
;
3357 for (i
= 0; i
< img_chunk_num
; i
++)
3359 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3360 region
->image_start_sector
= chunk
->img_start_sector
;
3361 region
->disk_start_sector
= chunk
->disk_start_sector
;
3367 /* Step3: Fill acpi checksum */
3369 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3371 /* load acpi table */
3372 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3373 grub_script_execute_sourcecode(cmd
);
3377 VENTOY_CMD_RETURN(0);
3380 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3386 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3387 g_ventoy_last_entry
= -1;
3392 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3398 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3403 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3405 const char *pos
= filename
+ 1;
3413 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3415 grub_strncpy((char *)data
, filename
, 128);
3426 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3429 char *device_name
= NULL
;
3430 grub_device_t dev
= NULL
;
3431 grub_fs_t fs
= NULL
;
3432 char buf
[128] = {0};
3438 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3442 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3444 device_name
= grub_file_get_device_name(args
[0]);
3447 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3451 dev
= grub_device_open(device_name
);
3454 debug("grub_device_open failed, %s\n", device_name
);
3458 fs
= grub_fs_probe(dev
);
3461 debug("grub_fs_probe failed, %s\n", device_name
);
3465 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3469 ventoy_set_env(args
[2], buf
);
3476 check_free(device_name
, grub_free
);
3477 check_free(dev
, grub_device_close
);
3482 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3492 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3493 if (!g_ventoy_part_info
)
3498 disk
= grub_disk_open(args
[0]);
3501 debug("Failed to open disk %s\n", args
[0]);
3505 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3506 grub_disk_close(disk
);
3508 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3509 dev
= grub_device_open(name
);
3512 /* make sure that we are running in a correct Ventoy device */
3513 ret
= ventoy_check_device(dev
);
3514 grub_device_close(dev
);
3525 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3528 grub_uint8_t zeroguid
[16] = {0};
3533 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3536 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3538 if (id
>= 1 && id
<= 128)
3540 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3548 if (id
>= 1 && id
<= 4)
3550 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3560 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3563 char *device_name
= NULL
;
3564 grub_device_t dev
= NULL
;
3565 grub_fs_t fs
= NULL
;
3572 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3576 device_name
= grub_file_get_device_name(args
[0]);
3579 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3583 dev
= grub_device_open(device_name
);
3586 debug("grub_device_open failed, %s\n", device_name
);
3590 fs
= grub_fs_probe(dev
);
3593 debug("grub_fs_probe failed, %s\n", device_name
);
3597 fs
->fs_label(dev
, &label
);
3600 ventoy_set_env(args
[1], label
);
3608 check_free(device_name
, grub_free
);
3609 check_free(dev
, grub_device_close
);
3614 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3618 grub_snprintf((char *)data
, 256, "%s", filename
);
3626 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3629 char *device_name
= NULL
;
3630 grub_device_t dev
= NULL
;
3631 grub_fs_t fs
= NULL
;
3632 char name
[256] ={0};
3638 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3642 device_name
= grub_file_get_device_name(args
[0]);
3645 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3649 dev
= grub_device_open(device_name
);
3652 debug("grub_device_open failed, %s\n", device_name
);
3656 fs
= grub_fs_probe(dev
);
3659 debug("grub_fs_probe failed, %s\n", device_name
);
3663 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3666 ventoy_set_env(args
[2], name
);
3673 check_free(device_name
, grub_free
);
3674 check_free(dev
, grub_device_close
);
3679 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3689 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3693 for (pos
= args
[0]; *pos
; pos
++)
3707 grub_env_set(args
[1], args
[0]);
3717 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3719 struct grub_video_mode_info info
;
3726 if (!g_video_mode_list
)
3728 ventoy_enum_video_mode();
3731 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3733 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3737 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3740 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3742 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3743 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3745 VENTOY_CMD_RETURN(0);
3748 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3750 struct grub_video_mode_info info
;
3757 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3759 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3763 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3766 grub_env_set(args
[0], buf
);
3768 VENTOY_CMD_RETURN(0);
3771 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3779 if (!g_video_mode_list
)
3784 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3785 if (id
< g_video_mode_num
)
3787 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3788 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3791 grub_env_set(args
[1], buf
);
3793 VENTOY_CMD_RETURN(0);
3796 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3798 grub_uint64_t size
= 0;
3801 char fullpath
[256] = {0};
3804 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3807 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3810 debug("grub_file_open failed <%s>\n", fullpath
);
3816 grub_file_close(file
);
3820 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3824 char fullpath
[256] = {0};
3827 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3830 file
= grub_file_open(fullpath
, type
);
3833 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3840 int ventoy_is_file_exist(const char *fmt
, ...)
3845 char buf
[256] = {0};
3847 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3851 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3854 grub_strncpy(pos
+ len
, "\" ]", 3);
3856 debug("script exec %s\n", buf
);
3858 if (0 == grub_script_execute_sourcecode(buf
))
3866 int ventoy_is_dir_exist(const char *fmt
, ...)
3871 char buf
[256] = {0};
3873 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
3877 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3880 grub_strncpy(pos
+ len
, "\" ]", 3);
3882 debug("script exec %s\n", buf
);
3884 if (0 == grub_script_execute_sourcecode(buf
))
3892 static int ventoy_env_init(void)
3896 grub_env_set("vtdebug_flag", "");
3898 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3899 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3900 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3901 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
3903 ventoy_filt_register(0, ventoy_wrapper_open
);
3905 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3908 g_grub_param
->grub_env_get
= grub_env_get
;
3909 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3910 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3911 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3912 grub_env_set("env_param", buf
);
3913 grub_env_set("ventoy_env_param", buf
);
3914 grub_env_export("ventoy_env_param");
3920 static cmd_para ventoy_cmds
[] =
3922 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3923 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3924 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3925 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3926 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3927 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3928 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3929 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3930 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3931 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3932 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3933 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3934 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3935 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3936 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3937 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3938 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3939 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3940 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
3941 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
3943 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
3944 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3945 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3946 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3947 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3948 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3949 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3951 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
3952 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
3953 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3954 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3955 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3956 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
3957 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
3958 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
3961 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3962 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
3963 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
3964 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
3965 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
3966 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
3967 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
3968 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
3969 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
3970 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
3971 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
3973 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
3974 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
3975 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
3976 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
3977 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
3978 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
3980 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3981 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3982 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
3983 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
3984 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
3985 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
3986 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
3987 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
3988 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
3989 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
3991 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
3992 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
3993 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
3994 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
3995 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
3996 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
3997 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
3998 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4000 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4001 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4002 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4005 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4006 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4007 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4009 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4010 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4011 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4014 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4015 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4016 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4017 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4018 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4019 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4020 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4021 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4023 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4024 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4025 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4031 GRUB_MOD_INIT(ventoy
)
4034 cmd_para
*cur
= NULL
;
4038 ventoy_arch_mode_init();
4040 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4042 cur
= ventoy_cmds
+ i
;
4043 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4044 cur
->summary
, cur
->description
, cur
->parser
);
4048 GRUB_MOD_FINI(ventoy
)
4052 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4054 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);