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
)
1714 grub_uint64_t offset
;
1719 struct grub_partition
*partition
;
1721 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1723 return ventoy_check_device_result(1 | 0x1000);
1726 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1727 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1728 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1730 #ifndef GRUB_MACHINE_EFI
1731 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1732 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1733 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1735 return ventoy_check_device_result(2 | 0x1000);
1744 /* We must have partition 2 */
1747 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1751 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1755 return ventoy_check_device_result(3 | 0x1000);
1758 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1760 grub_file_close(file
);
1761 return ventoy_check_device_result(4 | 0x1000);
1764 partition
= dev
->disk
->partition
;
1765 if (partition
->number
!= 0 || partition
->start
!= 2048)
1767 return ventoy_check_device_result(5);
1772 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1773 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1774 PartTbl
[1].SectorCount
!= 65536)
1776 grub_file_close(file
);
1777 return ventoy_check_device_result(6);
1782 offset
= partition
->start
+ partition
->len
;
1783 partition
= file
->device
->disk
->partition
;
1784 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1786 grub_file_close(file
);
1787 return ventoy_check_device_result(7);
1791 grub_file_close(file
);
1793 if (workaround
== 0)
1795 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1796 dev2
= grub_device_open(devname
);
1799 return ventoy_check_device_result(8);
1802 fs
= grub_fs_probe(dev2
);
1805 grub_device_close(dev2
);
1806 return ventoy_check_device_result(9);
1809 fs
->fs_label(dev2
, &label
);
1810 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1812 grub_device_close(dev2
);
1813 return ventoy_check_device_result(10);
1816 grub_device_close(dev2
);
1819 return ventoy_check_device_result(0);
1822 static int ventoy_set_default_menu(void)
1828 const char *strdata
= NULL
;
1829 img_info
*cur
= NULL
;
1830 img_info
*default_node
= NULL
;
1831 const char *default_image
= NULL
;
1833 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1834 if (default_image
&& default_image
[0] == '/')
1836 img_len
= grub_strlen(default_image
);
1838 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1840 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1852 if (0 == g_default_menu_mode
)
1854 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1858 def
= grub_strdup(default_image
);
1864 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1866 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1867 if (strdata
&& strdata
[0] == '/')
1869 pos
= def
+ grub_strlen(strdata
);
1880 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1883 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1887 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1895 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1899 grub_device_t dev
= NULL
;
1900 img_info
*cur
= NULL
;
1901 img_info
*tail
= NULL
;
1902 const char *strdata
= NULL
;
1903 char *device_name
= NULL
;
1905 img_iterator_node
*node
= NULL
;
1906 img_iterator_node
*tmp
= NULL
;
1912 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1915 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1917 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1920 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1921 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1923 g_filt_dot_underscore_file
= 1;
1926 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1927 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1929 g_sort_case_sensitive
= 1;
1932 device_name
= grub_file_get_device_name(args
[0]);
1938 g_enum_dev
= dev
= grub_device_open(device_name
);
1944 g_enum_fs
= fs
= grub_fs_probe(dev
);
1950 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1952 debug("unsupported fs:<%s>\n", fs
->name
);
1953 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1957 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1959 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1960 if (strdata
&& strdata
[0] == '1')
1962 g_default_menu_mode
= 1;
1965 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1967 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1969 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1970 if (strdata
&& strdata
[0] == '/')
1972 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1973 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1975 g_img_iterator_head
.dir
[len
++] = '/';
1977 g_img_iterator_head
.dirlen
= len
;
1981 g_img_iterator_head
.dirlen
= 1;
1982 grub_strcpy(g_img_iterator_head
.dir
, "/");
1985 g_img_iterator_head
.tail
= &tail
;
1987 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1989 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1992 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1993 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1995 g_tree_view_menu_style
= 1;
1998 ventoy_set_default_menu();
2000 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2002 ventoy_dynamic_tree_menu(node
);
2006 node
= g_img_iterator_head
.next
;
2014 /* sort image list by image name */
2015 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2017 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2019 if (ventoy_cmp_img(cur
, tail
) > 0)
2021 ventoy_swap_img(cur
, tail
);
2026 if (g_default_menu_mode
== 1)
2028 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2029 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2030 " echo 'return ...' \n"
2034 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2036 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2037 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2040 cur
->unsupport
? "[***********] " : "",
2041 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2043 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2046 g_tree_script_buf
[g_tree_script_pos
] = 0;
2047 g_list_script_buf
[g_list_script_pos
] = 0;
2049 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2050 grub_env_set(args
[1], buf
);
2054 check_free(device_name
, grub_free
);
2055 check_free(dev
, grub_device_close
);
2057 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2061 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2063 img_info
*next
= NULL
;
2064 img_info
*cur
= g_ventoy_img_list
;
2077 g_ventoy_img_list
= NULL
;
2078 g_ventoy_img_count
= 0;
2080 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2083 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2086 img_info
*cur
= g_ventoy_img_list
;
2090 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2092 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2095 img_id
= grub_strtol(args
[0], NULL
, 10);
2096 if (img_id
>= g_ventoy_img_count
)
2098 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2101 debug("Find image %ld name \n", img_id
);
2103 while (cur
&& img_id
> 0)
2111 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2114 debug("image name is %s\n", cur
->name
);
2116 grub_env_set(args
[1], cur
->name
);
2118 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2121 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2126 const char *id
= NULL
;
2127 img_info
*cur
= g_ventoy_img_list
;
2131 if (argc
< 1 || argc
> 2)
2133 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2136 id
= grub_env_get("chosen");
2138 pos
= grub_strstr(id
, "VID_");
2141 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2145 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2150 if (img_id
== cur
->id
)
2159 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2162 grub_env_set(args
[0], cur
->path
);
2166 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2167 grub_env_set(args
[1], value
);
2170 g_svd_replace_offset
= 0;
2172 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2175 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2182 device_name
= grub_file_get_device_name(filename
);
2194 pos2
= grub_strstr(pos
, ",");
2197 pos2
= grub_strstr(pos
, ")");
2205 disk
= grub_disk_open(pos
);
2208 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2209 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2210 grub_disk_close(disk
);
2217 grub_free(device_name
);
2221 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2223 eltorito_descriptor desc
;
2225 grub_memset(&desc
, 0, sizeof(desc
));
2226 grub_file_seek(file
, 17 * 2048);
2227 grub_file_read(file
, &desc
, sizeof(desc
));
2229 if (desc
.type
!= 0 || desc
.version
!= 1)
2234 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2235 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2243 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2247 grub_uint8_t buf
[512];
2249 grub_file_seek(file
, sector
* 2048);
2250 grub_file_read(file
, buf
, sizeof(buf
));
2252 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2254 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2258 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2263 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2265 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2267 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2271 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2273 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2278 debug("%s does not contain efi eltorito\n", file
->name
);
2282 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2285 const char *fs
= NULL
;
2286 const char *cdprompt
= NULL
;
2288 grub_uint8_t chksum
= 0;
2291 disk
= file
->device
->disk
;
2292 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2294 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2295 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2296 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2298 pos
= grub_strstr(file
->name
, "/");
2304 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2306 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2308 param
->vtoy_img_size
= file
->size
;
2310 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2311 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2313 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2315 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2316 param
->vtoy_reserved
[4] = 0;
2317 if (g_ventoy_chain_type
== 1) /* Windows */
2319 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2320 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2322 param
->vtoy_reserved
[4] = 1;
2326 fs
= ventoy_get_env("ventoy_fs_probe");
2327 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2329 param
->vtoy_reserved
[3] = 1;
2332 /* calculate checksum */
2333 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2335 chksum
+= *((grub_uint8_t
*)param
+ i
);
2337 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2342 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2344 grub_uint32_t i
= 0;
2345 grub_uint64_t total
= 0;
2346 ventoy_img_chunk
*chunk
= NULL
;
2348 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2350 chunk
= chunklist
->chunk
+ i
;
2352 if (chunk
->disk_start_sector
<= start
)
2354 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2358 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2361 if (total
!= ((file
->size
+ 511) / 512))
2363 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2370 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2374 grub_uint32_t i
= 0;
2375 grub_uint32_t sector
= 0;
2376 grub_uint32_t count
= 0;
2377 grub_off_t size
= 0;
2378 grub_off_t read
= 0;
2380 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2381 if (fs_type
== ventoy_fs_exfat
)
2383 grub_fat_get_file_chunk(start
, file
, chunklist
);
2385 else if (fs_type
== ventoy_fs_ext
)
2387 grub_ext_get_file_chunk(start
, file
, chunklist
);
2391 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2392 file
->read_hook_data
= chunklist
;
2394 for (size
= file
->size
; size
> 0; size
-= read
)
2396 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2397 grub_file_read(file
, NULL
, read
);
2400 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2402 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2403 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2406 if (ventoy_fs_udf
== fs_type
)
2408 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2410 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2411 chunklist
->chunk
[i
].img_start_sector
= sector
;
2412 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2418 len
= (int)grub_strlen(file
->name
);
2419 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2420 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2421 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2422 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2424 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2426 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2436 chunklist
->chunk
[i
].img_start_sector
= sector
;
2437 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2445 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2449 grub_disk_addr_t start
;
2454 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2457 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2460 g_conf_replace_node
= NULL
;
2461 g_conf_replace_offset
= 0;
2463 if (g_img_chunk_list
.chunk
)
2465 grub_free(g_img_chunk_list
.chunk
);
2468 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2470 grub_file_close(file
);
2471 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2474 /* get image chunk data */
2475 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2476 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2477 if (NULL
== g_img_chunk_list
.chunk
)
2479 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2482 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2483 g_img_chunk_list
.cur_chunk
= 0;
2485 start
= file
->device
->disk
->partition
->start
;
2487 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2489 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2490 grub_file_close(file
);
2494 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2497 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2498 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2501 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2503 grub_uint64_t offset
= 0;
2504 grub_uint32_t align
= 0;
2505 grub_file_t file
= NULL
;
2506 conf_replace
*node
= NULL
;
2512 debug("select conf replace argc:%d\n", argc
);
2519 node
= ventoy_plugin_find_conf_replace(args
[1]);
2522 debug("Conf replace not found for %s\n", args
[1]);
2526 debug("Find conf replace for %s\n", args
[1]);
2528 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2531 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2535 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2536 grub_file_close(file
);
2538 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2541 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2545 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2547 if (align
> vtoy_max_replace_file_size
)
2549 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2553 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2554 g_conf_replace_new_len
= (int)file
->size
;
2555 g_conf_replace_new_len_align
= align
;
2557 g_conf_replace_node
= node
;
2558 g_conf_replace_offset
= offset
+ 2;
2560 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2565 grub_file_close(file
);
2567 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2570 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2575 char configfile
[128];
2576 install_template
*node
= NULL
;
2582 debug("select auto installation argc:%d\n", argc
);
2589 node
= ventoy_plugin_find_install_template(args
[0]);
2592 debug("Auto install template not found for %s\n", args
[0]);
2596 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2598 node
->cursel
= node
->autosel
- 1;
2599 debug("Auto install template auto select %d\n", node
->autosel
);
2603 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2609 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2610 " echo %s\n}\n", "123");
2612 for (i
= 0; i
< node
->templatenum
; i
++)
2614 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2616 node
->templatepath
[i
].path
);
2619 g_ventoy_menu_esc
= 1;
2620 g_ventoy_suppress_esc
= 1;
2622 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2623 grub_script_execute_sourcecode(configfile
);
2625 g_ventoy_menu_esc
= 0;
2626 g_ventoy_suppress_esc
= 0;
2630 node
->cursel
= g_ventoy_last_entry
- 1;
2632 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2635 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2640 char configfile
[128];
2641 persistence_config
*node
;
2647 debug("select persistence argc:%d\n", argc
);
2654 node
= ventoy_plugin_find_persistent(args
[0]);
2657 debug("Persistence image not found for %s\n", args
[0]);
2661 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2663 node
->cursel
= node
->autosel
- 1;
2664 debug("Persistence image auto select %d\n", node
->autosel
);
2668 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2674 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2675 " echo %s\n}\n", "123");
2677 for (i
= 0; i
< node
->backendnum
; i
++)
2679 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2681 node
->backendpath
[i
].path
);
2685 g_ventoy_menu_esc
= 1;
2686 g_ventoy_suppress_esc
= 1;
2688 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2689 grub_script_execute_sourcecode(configfile
);
2691 g_ventoy_menu_esc
= 0;
2692 g_ventoy_suppress_esc
= 0;
2696 node
->cursel
= g_ventoy_last_entry
- 1;
2698 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2701 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2704 ventoy_img_chunk
*cur
;
2710 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2712 cur
= g_img_chunk_list
.chunk
+ i
;
2713 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2714 cur
->img_start_sector
, cur
->img_end_sector
,
2715 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2719 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2722 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2726 ventoy_img_chunk_list chunklist
;
2731 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2734 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2737 /* get image chunk data */
2738 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2739 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2740 if (NULL
== chunklist
.chunk
)
2742 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2745 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2746 chunklist
.cur_chunk
= 0;
2748 ventoy_get_block_list(file
, &chunklist
, 0);
2750 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2752 grub_printf("########## UNSUPPORTED ###############\n");
2755 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2757 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2759 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2760 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2763 grub_printf("\n==================================\n");
2765 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2767 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2768 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2769 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2770 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2771 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2775 grub_free(chunklist
.chunk
);
2776 grub_file_close(file
);
2778 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2781 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2784 ventoy_grub_param_file_replace
*replace
= NULL
;
2792 replace
= &(g_grub_param
->file_replace
);
2793 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2795 replace
->old_name_cnt
= 0;
2796 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2798 replace
->old_name_cnt
++;
2799 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2802 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2805 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2808 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2816 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2817 grub_printf("%s", g_list_script_buf
);
2821 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2822 grub_printf("%s", g_tree_script_buf
);
2828 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2830 img_info
*cur
= g_ventoy_img_list
;
2838 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2839 grub_printf("name:<%s>\n\n", cur
->name
);
2846 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2852 ventoy_plugin_dump_injection();
2857 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2863 ventoy_plugin_dump_auto_install();
2868 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2874 ventoy_plugin_dump_persistence();
2879 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2890 if (args
[0][0] == '0')
2892 return g_ventoy_memdisk_mode
? 0 : 1;
2894 else if (args
[0][0] == '1')
2896 return g_ventoy_iso_raw
? 0 : 1;
2898 else if (args
[0][0] == '2')
2900 return g_ventoy_iso_uefi_drv
? 0 : 1;
2906 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2908 static int configfile_mode
= 0;
2909 char memfile
[128] = {0};
2916 * args[0]: 0:normal 1:configfile
2917 * args[1]: 0:list_buf 1:tree_buf
2922 debug("Invalid argc %d\n", argc
);
2926 if (args
[0][0] == '0')
2928 if (args
[1][0] == '0')
2930 grub_script_execute_sourcecode(g_list_script_buf
);
2934 grub_script_execute_sourcecode(g_tree_script_buf
);
2939 if (configfile_mode
)
2941 debug("Now already in F3 mode %d\n", configfile_mode
);
2945 if (args
[1][0] == '0')
2947 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2948 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2952 g_ventoy_last_entry
= -1;
2953 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2954 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2957 configfile_mode
= 1;
2958 grub_script_execute_sourcecode(memfile
);
2959 configfile_mode
= 0;
2965 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2976 g_ventoy_case_insensitive
= 1;
2977 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2978 g_ventoy_case_insensitive
= 0;
2984 grub_file_close(file
);
2990 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2995 const char *isopath
= NULL
;
2997 ventoy_mbr_head mbr
;
3004 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3007 isopath
= grub_env_get("vtoy_iso_part");
3010 debug("isopath is null %p\n", isopath
);
3014 debug("isopath is %s\n", isopath
);
3016 for (id
= 0; id
< 30 && (find
== 0); id
++)
3018 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3019 if (grub_strstr(isopath
, hdname
))
3021 debug("skip %s ...\n", hdname
);
3025 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3027 disk
= grub_disk_open(hdname
);
3030 debug("%s not exist\n", hdname
);
3034 grub_memset(&mbr
, 0, sizeof(mbr
));
3035 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3037 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3039 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3040 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3043 grub_env_set(args
[0], hdname
);
3047 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3051 debug("read %s failed\n", hdname
);
3054 grub_disk_close(disk
);
3060 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3071 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3074 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3077 debug("failed to open file %s\n", args
[0]);
3081 buf
= grub_malloc(len
);
3088 grub_file_read(file
, buf
, len
- 1);
3090 ventoy_get_line(buf
);
3091 ventoy_set_env(args
[1], buf
);
3095 grub_check_free(buf
);
3096 grub_file_close(file
);
3101 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3106 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3107 "0 %llu linear /dev/ventoy %llu\n",
3108 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3113 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3115 char *device_name
= NULL
;
3116 grub_device_t dev
= NULL
;
3121 g_part_list_pos
= 0;
3122 grub_env_unset("vtoy_img_part_file");
3129 device_name
= grub_file_get_device_name(args
[0]);
3132 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3136 dev
= grub_device_open(device_name
);
3139 debug("grub_device_open failed, %s\n", device_name
);
3143 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3145 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3146 grub_env_set("vtoy_img_part_file", buf
);
3150 check_free(device_name
, grub_free
);
3151 check_free(dev
, grub_device_close
);
3157 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3168 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3171 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3174 debug("failed to open file %s\n", args
[0]);
3178 buf
= grub_malloc(file
->size
+ 1);
3184 buf
[file
->size
] = 0;
3185 grub_file_read(file
, buf
, file
->size
);
3187 if (grub_strstr(buf
, args
[1]))
3194 grub_check_free(buf
);
3195 grub_file_close(file
);
3200 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3205 ventoy_iso9660_vd pvd
;
3212 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3215 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3218 debug("failed to open file %s\n", args
[0]);
3222 grub_file_seek(file
, 16 * 2048);
3223 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3224 if (len
!= sizeof(pvd
))
3226 debug("failed to read pvd %d\n", len
);
3230 grub_memset(buf
, 0, sizeof(buf
));
3231 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3232 ventoy_set_env(args
[1], buf
);
3234 grub_memset(buf
, 0, sizeof(buf
));
3235 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3236 ventoy_set_env(args
[2], buf
);
3239 grub_file_close(file
);
3244 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3255 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3258 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3261 debug("failed to open file %s\n", args
[0]);
3265 grub_memset(buf
, 0, sizeof(buf
));
3266 grub_file_seek(file
, 16 * 2048 + 813);
3267 len
= (int)grub_file_read(file
, buf
, 17);
3270 debug("failed to read create date %d\n", len
);
3274 ventoy_set_env(args
[1], buf
);
3277 grub_file_close(file
);
3282 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3288 ventoy_env_hook_root(1);
3293 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3299 ventoy_env_hook_root(0);
3304 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3311 int image_sector_size
;
3313 ventoy_chain_head
*chain
;
3314 ventoy_img_chunk
*chunk
;
3315 ventoy_os_param
*osparam
;
3316 ventoy_image_location
*location
;
3317 ventoy_image_disk_region
*region
;
3318 struct grub_acpi_table_header
*acpi
;
3327 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3329 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3335 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3337 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3339 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3343 img_chunk_num
= chain
->img_chunk_num
;
3345 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3346 datalen
= sizeof(ventoy_os_param
) + loclen
;
3348 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3349 acpi
= grub_zalloc(buflen
);
3355 /* Step1: Fill acpi table header */
3356 grub_memcpy(acpi
->signature
, "VTOY", 4);
3357 acpi
->length
= buflen
;
3359 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3360 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3362 acpi
->creator_id
[0] = 1;
3363 acpi
->creator_rev
= 1;
3365 /* Step2: Fill data */
3366 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3367 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3368 osparam
->vtoy_img_location_addr
= 0;
3369 osparam
->vtoy_img_location_len
= loclen
;
3370 osparam
->chksum
= 0;
3371 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3373 location
= (ventoy_image_location
*)(osparam
+ 1);
3374 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3375 location
->image_sector_size
= image_sector_size
;
3376 location
->disk_sector_size
= chain
->disk_sector_size
;
3377 location
->region_count
= img_chunk_num
;
3379 region
= location
->regions
;
3380 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3381 if (512 == image_sector_size
)
3383 for (i
= 0; i
< img_chunk_num
; i
++)
3385 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3386 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3387 region
->disk_start_sector
= chunk
->disk_start_sector
;
3394 for (i
= 0; i
< img_chunk_num
; i
++)
3396 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3397 region
->image_start_sector
= chunk
->img_start_sector
;
3398 region
->disk_start_sector
= chunk
->disk_start_sector
;
3404 /* Step3: Fill acpi checksum */
3406 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3408 /* load acpi table */
3409 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3410 grub_script_execute_sourcecode(cmd
);
3414 VENTOY_CMD_RETURN(0);
3417 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3423 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3424 g_ventoy_last_entry
= -1;
3429 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3435 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3440 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3442 const char *pos
= filename
+ 1;
3450 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3452 grub_strncpy((char *)data
, filename
, 128);
3463 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3466 char *device_name
= NULL
;
3467 grub_device_t dev
= NULL
;
3468 grub_fs_t fs
= NULL
;
3469 char buf
[128] = {0};
3475 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3479 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3481 device_name
= grub_file_get_device_name(args
[0]);
3484 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3488 dev
= grub_device_open(device_name
);
3491 debug("grub_device_open failed, %s\n", device_name
);
3495 fs
= grub_fs_probe(dev
);
3498 debug("grub_fs_probe failed, %s\n", device_name
);
3502 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3506 ventoy_set_env(args
[2], buf
);
3513 check_free(device_name
, grub_free
);
3514 check_free(dev
, grub_device_close
);
3519 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3529 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3530 if (!g_ventoy_part_info
)
3535 disk
= grub_disk_open(args
[0]);
3538 debug("Failed to open disk %s\n", args
[0]);
3542 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3543 grub_disk_close(disk
);
3545 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3546 dev
= grub_device_open(name
);
3549 /* make sure that we are running in a correct Ventoy device */
3550 ret
= ventoy_check_device(dev
);
3551 grub_device_close(dev
);
3562 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3565 grub_uint8_t zeroguid
[16] = {0};
3570 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3573 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3575 if (id
>= 1 && id
<= 128)
3577 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3585 if (id
>= 1 && id
<= 4)
3587 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3597 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3600 char *device_name
= NULL
;
3601 grub_device_t dev
= NULL
;
3602 grub_fs_t fs
= NULL
;
3609 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3613 device_name
= grub_file_get_device_name(args
[0]);
3616 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3620 dev
= grub_device_open(device_name
);
3623 debug("grub_device_open failed, %s\n", device_name
);
3627 fs
= grub_fs_probe(dev
);
3630 debug("grub_fs_probe failed, %s\n", device_name
);
3634 fs
->fs_label(dev
, &label
);
3637 ventoy_set_env(args
[1], label
);
3645 check_free(device_name
, grub_free
);
3646 check_free(dev
, grub_device_close
);
3651 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3655 grub_snprintf((char *)data
, 256, "%s", filename
);
3663 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3666 char *device_name
= NULL
;
3667 grub_device_t dev
= NULL
;
3668 grub_fs_t fs
= NULL
;
3669 char name
[256] ={0};
3675 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3679 device_name
= grub_file_get_device_name(args
[0]);
3682 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3686 dev
= grub_device_open(device_name
);
3689 debug("grub_device_open failed, %s\n", device_name
);
3693 fs
= grub_fs_probe(dev
);
3696 debug("grub_fs_probe failed, %s\n", device_name
);
3700 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3703 ventoy_set_env(args
[2], name
);
3710 check_free(device_name
, grub_free
);
3711 check_free(dev
, grub_device_close
);
3716 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3726 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3730 for (pos
= args
[0]; *pos
; pos
++)
3744 grub_env_set(args
[1], args
[0]);
3754 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3756 struct grub_video_mode_info info
;
3763 if (!g_video_mode_list
)
3765 ventoy_enum_video_mode();
3768 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3770 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3774 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3777 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3779 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3780 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3782 VENTOY_CMD_RETURN(0);
3785 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3787 struct grub_video_mode_info info
;
3794 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3796 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3800 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3803 grub_env_set(args
[0], buf
);
3805 VENTOY_CMD_RETURN(0);
3808 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3816 if (!g_video_mode_list
)
3821 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3822 if (id
< g_video_mode_num
)
3824 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3825 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3828 grub_env_set(args
[1], buf
);
3830 VENTOY_CMD_RETURN(0);
3833 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3835 grub_uint64_t size
= 0;
3838 char fullpath
[256] = {0};
3841 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3844 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3847 debug("grub_file_open failed <%s>\n", fullpath
);
3853 grub_file_close(file
);
3857 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3861 char fullpath
[256] = {0};
3864 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3867 file
= grub_file_open(fullpath
, type
);
3870 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3877 int ventoy_is_file_exist(const char *fmt
, ...)
3882 char buf
[256] = {0};
3884 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3888 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3891 grub_strncpy(pos
+ len
, "\" ]", 3);
3893 debug("script exec %s\n", buf
);
3895 if (0 == grub_script_execute_sourcecode(buf
))
3903 int ventoy_is_dir_exist(const char *fmt
, ...)
3908 char buf
[256] = {0};
3910 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
3914 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3917 grub_strncpy(pos
+ len
, "\" ]", 3);
3919 debug("script exec %s\n", buf
);
3921 if (0 == grub_script_execute_sourcecode(buf
))
3929 static int ventoy_env_init(void)
3933 grub_env_set("vtdebug_flag", "");
3935 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3936 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3937 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3938 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
3940 ventoy_filt_register(0, ventoy_wrapper_open
);
3942 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3945 g_grub_param
->grub_env_get
= grub_env_get
;
3946 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3947 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3948 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3949 grub_env_set("env_param", buf
);
3950 grub_env_set("ventoy_env_param", buf
);
3951 grub_env_export("ventoy_env_param");
3957 static cmd_para ventoy_cmds
[] =
3959 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3960 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3961 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3962 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3963 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3964 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3965 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3966 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3967 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3968 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3969 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3970 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3971 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3972 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3973 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3974 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3975 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3976 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3977 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
3978 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
3980 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
3981 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3982 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3983 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3984 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3985 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3986 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3988 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
3989 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
3990 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3991 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3992 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3993 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
3994 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
3995 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
3998 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3999 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4000 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4001 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4002 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4003 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4004 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4005 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4006 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4007 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4008 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4010 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4011 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4012 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4013 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4014 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4015 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4017 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4018 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4019 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4020 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4021 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4022 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4023 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4024 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4025 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4026 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4028 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4029 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4030 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4031 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4032 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4033 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4034 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4035 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4037 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4038 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4039 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4042 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4043 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4044 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4046 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4047 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4048 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4051 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4052 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4053 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4054 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4055 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4056 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4057 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4058 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4060 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4061 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4062 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4068 GRUB_MOD_INIT(ventoy
)
4071 cmd_para
*cur
= NULL
;
4075 ventoy_arch_mode_init();
4077 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4079 cur
= ventoy_cmds
+ i
;
4080 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4081 cur
->summary
, cur
->description
, cur
->parser
);
4085 GRUB_MOD_FINI(ventoy
)
4089 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4091 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);