1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/misc.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
36 #include <grub/misc.h>
37 #include <grub/kernel.h>
38 #ifdef GRUB_MACHINE_EFI
39 #include <grub/efi/efi.h>
41 #include <grub/time.h>
42 #include <grub/video.h>
43 #include <grub/acpi.h>
44 #include <grub/charset.h>
45 #include <grub/crypto.h>
46 #include <grub/lib/crc.h>
47 #include <grub/ventoy.h>
48 #include "ventoy_def.h"
51 GRUB_MOD_LICENSE ("GPLv3+");
53 int g_ventoy_debug
= 0;
54 static int g_efi_os
= 0xFF;
55 initrd_info
*g_initrd_img_list
= NULL
;
56 initrd_info
*g_initrd_img_tail
= NULL
;
57 int g_initrd_img_count
= 0;
58 int g_valid_initrd_count
= 0;
59 int g_default_menu_mode
= 0;
60 int g_filt_dot_underscore_file
= 0;
61 int g_sort_case_sensitive
= 0;
62 int g_tree_view_menu_style
= 0;
63 static grub_file_t g_old_file
;
64 static int g_ventoy_last_entry_back
;
65 static grub_uint32_t g_ventoy_plat_data
;
68 char g_img_swap_tmp_buf
[1024];
69 img_info g_img_swap_tmp
;
70 img_info
*g_ventoy_img_list
= NULL
;
72 int g_ventoy_img_count
= 0;
74 grub_device_t g_enum_dev
= NULL
;
75 grub_fs_t g_enum_fs
= NULL
;
76 img_iterator_node g_img_iterator_head
;
77 img_iterator_node
*g_img_iterator_tail
= NULL
;
79 grub_uint8_t g_ventoy_break_level
= 0;
80 grub_uint8_t g_ventoy_debug_level
= 0;
81 grub_uint8_t g_ventoy_chain_type
= 0;
83 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
84 grub_uint32_t g_ventoy_cpio_size
= 0;
85 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
86 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
88 int g_plugin_image_list
= 0;
90 ventoy_grub_param
*g_grub_param
= NULL
;
92 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
94 ventoy_img_chunk_list g_img_chunk_list
;
96 int g_wimboot_enable
= 0;
97 ventoy_img_chunk_list g_wimiso_chunk_list
;
98 char *g_wimiso_path
= NULL
;
100 int g_vhdboot_enable
= 0;
102 grub_uint64_t g_conf_replace_offset
= 0;
103 grub_uint64_t g_svd_replace_offset
= 0;
104 conf_replace
*g_conf_replace_node
= NULL
;
105 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
106 int g_conf_replace_new_len
= 0;
107 int g_conf_replace_new_len_align
= 0;
109 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
110 grub_uint64_t g_ventoy_disk_size
= 0;
112 static char *g_tree_script_buf
= NULL
;
113 static int g_tree_script_pos
= 0;
115 static char *g_list_script_buf
= NULL
;
116 static int g_list_script_pos
= 0;
118 static char *g_part_list_buf
= NULL
;
119 static int g_part_list_pos
= 0;
121 static int g_video_mode_max
= 0;
122 static int g_video_mode_num
= 0;
123 static ventoy_video_mode
*g_video_mode_list
= NULL
;
125 static const char *g_menu_class
[] =
127 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
130 static const char *g_menu_prefix
[] =
132 "iso", "wim", "efi", "img", "vhd", "vtoy"
135 void ventoy_debug(const char *fmt
, ...)
139 va_start (args
, fmt
);
140 grub_vprintf (fmt
, args
);
144 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
154 for (i
= 0; i
< 16; i
++)
156 grub_printf("%02x ", guid
[i
]);
161 int ventoy_is_efi_os(void)
165 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
171 static int ventoy_get_fs_type(const char *fs
)
175 return ventoy_fs_max
;
177 else if (grub_strncmp(fs
, "exfat", 5) == 0)
179 return ventoy_fs_exfat
;
181 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
183 return ventoy_fs_ntfs
;
185 else if (grub_strncmp(fs
, "ext", 3) == 0)
187 return ventoy_fs_ext
;
189 else if (grub_strncmp(fs
, "xfs", 3) == 0)
191 return ventoy_fs_xfs
;
193 else if (grub_strncmp(fs
, "udf", 3) == 0)
195 return ventoy_fs_udf
;
197 else if (grub_strncmp(fs
, "fat", 3) == 0)
199 return ventoy_fs_fat
;
202 return ventoy_fs_max
;
205 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
224 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
226 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
230 static grub_err_t
ventoy_fs_close(grub_file_t file
)
232 grub_file_close(g_old_file
);
233 grub_free(file
->data
);
241 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
247 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
252 for (i
= 0; i
< g_video_mode_num
; i
++)
254 if (g_video_mode_list
[i
].width
== info
->width
&&
255 g_video_mode_list
[i
].height
== info
->height
&&
256 g_video_mode_list
[i
].bpp
== info
->bpp
)
262 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
263 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
264 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
267 if (g_video_mode_num
== g_video_mode_max
)
269 g_video_mode_max
*= 2;
270 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
276 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
278 if (v1
->bpp
== v2
->bpp
)
280 if (v1
->width
== v2
->width
)
282 if (v1
->height
== v2
->height
)
288 return (v1
->height
< v2
->height
) ? -1 : 1;
293 return (v1
->width
< v2
->width
) ? -1 : 1;
298 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
302 static int ventoy_enum_video_mode(void)
305 grub_video_adapter_t adapter
;
306 grub_video_driver_id_t id
;
307 ventoy_video_mode mode
;
309 g_video_mode_num
= 0;
310 g_video_mode_max
= 1024;
311 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
312 if (!g_video_mode_list
)
317 #ifdef GRUB_MACHINE_PCBIOS
318 grub_dl_load ("vbe");
321 id
= grub_video_get_driver_id ();
323 FOR_VIDEO_ADAPTERS (adapter
)
325 if (!adapter
->iterate
||
326 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
327 adapter
->init() != GRUB_ERR_NONE
)))
332 adapter
->iterate(ventoy_video_hook
, NULL
);
334 if (adapter
->id
!= id
)
340 /* sort video mode */
341 for (i
= 0; i
< g_video_mode_num
; i
++)
342 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
344 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
346 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
347 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
348 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
352 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
355 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
359 static struct grub_fs vtoy_fs
=
364 .fs_read
= ventoy_fs_read
,
365 .fs_close
= ventoy_fs_close
,
375 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
381 file
->data
= grub_malloc(rawFile
->size
+ 4096);
387 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
388 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
390 g_old_file
= rawFile
;
392 file
->size
= rawFile
->size
+ len
;
393 file
->device
= rawFile
->device
;
395 file
->not_easily_seekable
= 1;
400 static int ventoy_check_decimal_var(const char *name
, long *value
)
402 const char *value_str
= NULL
;
404 value_str
= grub_env_get(name
);
405 if (NULL
== value_str
)
407 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
410 if (!ventoy_is_decimal(value_str
))
412 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
415 *value
= grub_strtol(value_str
, NULL
, 10);
417 return GRUB_ERR_NONE
;
420 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
424 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
427 if (0 == grub_strcmp(args
[0], "on"))
430 grub_env_set("vtdebug_flag", "debug");
435 grub_env_set("vtdebug_flag", "");
438 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
441 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
445 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
447 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
448 grub_printf(" level:\r\n");
449 grub_printf(" 01/11: busybox / (+cat log)\r\n");
450 grub_printf(" 02/12: initrd / (+cat log)\r\n");
451 grub_printf(" 03/13: hook / (+cat log)\r\n");
453 grub_printf(" debug:\r\n");
454 grub_printf(" 0: debug is off\r\n");
455 grub_printf(" 1: debug is on\r\n");
457 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
460 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
462 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
464 g_ventoy_debug_level
= 1;
467 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
470 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
479 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
482 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
514 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
519 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
521 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
524 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
529 value_long
+= grub_strtol(args
[1], NULL
, 10);
531 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
532 grub_env_set(args
[0], buf
);
534 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
537 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
552 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
555 debug("failed to open file <%s> for udf check\n", args
[0]);
559 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
561 grub_env_set(args
[1], buf
);
563 grub_file_close(file
);
569 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
577 g_wimboot_enable
= 0;
578 grub_check_free(g_wimiso_path
);
579 grub_check_free(g_wimiso_chunk_list
.chunk
);
581 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
587 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
588 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
589 if (NULL
== g_wimiso_chunk_list
.chunk
)
591 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
594 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
595 g_wimiso_chunk_list
.cur_chunk
= 0;
597 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
599 g_wimboot_enable
= 1;
600 g_wimiso_path
= grub_strdup(args
[0]);
602 grub_file_close(file
);
607 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
613 grub_uint32_t offset
;
615 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
618 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
622 len
= (int)file
->size
;
624 data
= (char *)grub_malloc(file
->size
);
630 grub_file_read(file
, data
, file
->size
);
631 grub_file_close(file
);
633 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
634 grub_script_execute_sourcecode(exec
);
636 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
637 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
638 grub_file_close(file
);
640 grub_script_execute_sourcecode("loopback -d efiboot");
644 *direntoff
= offset
+ 2;
649 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
659 ventoy_iso9660_override
*dirent
;
668 totlen
= sizeof(ventoy_chain_head
);
670 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
672 debug("failed to load efiboot template %d\n", len
);
678 debug("efiboot template len:%d offset:%d\n", len
, offset
);
680 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
683 debug("failed to open file <%s>\n", args
[0]);
687 totlen
+= ventoy_align_2k(file
->size
);
689 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
690 dirent
->first_sector
= len
/ 2048;
691 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
692 dirent
->size
= (grub_uint32_t
)file
->size
;
693 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
695 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
697 #ifdef GRUB_MACHINE_EFI
698 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
700 data
= (char *)grub_malloc(totlen
);
703 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
705 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
706 grub_check_free(buf
);
708 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
709 grub_file_close(file
);
711 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
712 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
713 grub_env_set(name
, value
);
715 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
716 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
717 grub_env_set(name
, value
);
722 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
739 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
742 debug("failed to open file <%s>\n", args
[0]);
746 #ifdef GRUB_MACHINE_EFI
747 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
749 buf
= (char *)grub_malloc(file
->size
);
752 grub_file_read(file
, buf
, file
->size
);
754 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
755 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
756 grub_env_set(name
, value
);
758 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
759 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
760 grub_env_set(name
, value
);
762 grub_file_close(file
);
768 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
786 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
789 debug("failed to open file <%s> for udf check\n", args
[0]);
793 headlen
= sizeof(ventoy_chain_head
);
795 #ifdef GRUB_MACHINE_EFI
796 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
798 buf
= (char *)grub_malloc(headlen
+ file
->size
);
801 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
803 grub_file_read(file
, buf
+ headlen
, file
->size
);
805 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
806 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
807 grub_env_set(name
, value
);
809 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
810 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
811 grub_env_set(name
, value
);
813 grub_file_close(file
);
819 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
828 if (args
[0][0] == '1')
830 grub_iso9660_set_nojoliet(1);
834 grub_iso9660_set_nojoliet(0);
840 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
845 grub_uint8_t buf
[32];
856 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
859 debug("failed to open file <%s> for udf check\n", args
[0]);
863 for (i
= 16; i
< 32; i
++)
865 grub_file_seek(file
, i
* 2048);
866 grub_file_read(file
, buf
, sizeof(buf
));
874 grub_file_seek(file
, i
* 2048);
875 grub_file_read(file
, buf
, sizeof(buf
));
877 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
880 grub_file_seek(file
, i
* 2048);
881 grub_file_read(file
, buf
, sizeof(buf
));
883 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
884 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
890 grub_file_close(file
);
892 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
897 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
899 long value_long1
= 0;
900 long value_long2
= 0;
902 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
904 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
907 value_long1
= grub_strtol(args
[0], NULL
, 10);
908 value_long2
= grub_strtol(args
[2], NULL
, 10);
910 if (0 == grub_strcmp(args
[1], "eq"))
912 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
914 else if (0 == grub_strcmp(args
[1], "ne"))
916 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
918 else if (0 == grub_strcmp(args
[1], "gt"))
920 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
922 else if (0 == grub_strcmp(args
[1], "lt"))
924 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
926 else if (0 == grub_strcmp(args
[1], "ge"))
928 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
930 else if (0 == grub_strcmp(args
[1], "le"))
932 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
936 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
942 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
949 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
952 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
953 pos
= grub_strstr(buf
, ",");
959 grub_env_set(args
[1], buf
);
961 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
964 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
970 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
976 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
979 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
981 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
982 if (0 == grub_script_execute_sourcecode(buf
))
984 debug("file %s exist, ventoy_compatible YES\n", buf
);
985 grub_env_set("ventoy_compatible", "YES");
986 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
990 debug("file %s NOT exist\n", buf
);
994 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
995 pos
= grub_strstr(buf
, ")");
1001 disk
= grub_disk_open(buf
);
1004 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1005 grub_disk_close(disk
);
1007 g_img_swap_tmp_buf
[703] = 0;
1008 for (i
= 318; i
< 703; i
++)
1010 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1011 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1013 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1014 grub_env_set("ventoy_compatible", "YES");
1015 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1021 debug("failed to open disk <%s>\n", buf
);
1024 grub_env_set("ventoy_compatible", "NO");
1025 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1028 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1034 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1036 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1039 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1044 if (0 == g_sort_case_sensitive
)
1046 if (grub_islower(c1
))
1048 c1
= c1
- 'a' + 'A';
1051 if (grub_islower(c2
))
1053 c2
= c2
- 'a' + 'A';
1066 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1072 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1074 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1077 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1082 if (0 == g_sort_case_sensitive
)
1084 if (grub_islower(c1
))
1086 c1
= c1
- 'a' + 'A';
1089 if (grub_islower(c2
))
1091 c2
= c2
- 'a' + 'A';
1104 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1106 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1108 grub_memcpy(img1
, img2
, sizeof(img_info
));
1109 img1
->next
= g_img_swap_tmp
.next
;
1110 img1
->prev
= g_img_swap_tmp
.prev
;
1112 g_img_swap_tmp
.next
= img2
->next
;
1113 g_img_swap_tmp
.prev
= img2
->prev
;
1114 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1117 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1121 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1129 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1133 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1143 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1152 img_iterator_node
*tmp
;
1153 img_iterator_node
*new_node
;
1154 img_iterator_node
*node
= (img_iterator_node
*)data
;
1156 len
= grub_strlen(filename
);
1160 if ((len
== 1 && filename
[0] == '.') ||
1161 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1166 if (!ventoy_img_name_valid(filename
, len
))
1171 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1176 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1178 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1179 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1182 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1187 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1190 new_node
->plugin_list_index
= index
;
1191 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1193 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1196 debug("Directory %s ignored...\n", new_node
->dir
);
1197 grub_free(new_node
);
1201 new_node
->tail
= node
->tail
;
1203 new_node
->parent
= node
;
1204 if (!node
->firstchild
)
1206 node
->firstchild
= new_node
;
1209 if (g_img_iterator_tail
)
1211 g_img_iterator_tail
->next
= new_node
;
1212 g_img_iterator_tail
= new_node
;
1216 g_img_iterator_head
.next
= new_node
;
1217 g_img_iterator_tail
= new_node
;
1223 debug("Find a file %s\n", filename
);
1229 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1231 type
= img_type_iso
;
1233 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1235 type
= img_type_wim
;
1237 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1238 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1240 type
= img_type_vhd
;
1242 #ifdef GRUB_MACHINE_EFI
1243 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1245 type
= img_type_efi
;
1248 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1250 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1252 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1253 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1258 type
= img_type_img
;
1260 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1262 type
= img_type_vtoy
;
1269 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1274 if (g_plugin_image_list
)
1276 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1277 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1278 if (VENTOY_IMG_WHITE_LIST
== g_plugin_image_list
&& index
== 0)
1280 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1283 else if (VENTOY_IMG_BLACK_LIST
== g_plugin_image_list
&& index
> 0)
1285 debug("File %s found in image_blacklist plugin config...\n", g_img_swap_tmp_buf
);
1290 img
= grub_zalloc(sizeof(img_info
));
1294 img
->plugin_list_index
= index
;
1295 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1297 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1299 img
->size
= info
->size
;
1302 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1305 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1307 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1312 if (g_ventoy_img_list
)
1314 tail
= *(node
->tail
);
1320 g_ventoy_img_list
= img
;
1323 img
->id
= g_ventoy_img_count
;
1325 if (node
&& NULL
== node
->firstiso
)
1327 node
->firstiso
= img
;
1338 *((img_info
**)(node
->tail
)) = img
;
1339 g_ventoy_img_count
++;
1341 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1342 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1345 img
->class = g_menu_class
[type
];
1347 img
->menu_prefix
= g_menu_prefix
[type
];
1349 if (img_type_iso
== type
)
1351 if (ventoy_plugin_check_memdisk(img
->path
))
1353 img
->menu_prefix
= "miso";
1357 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1364 static int ventoy_arch_mode_init(void)
1366 #ifdef GRUB_MACHINE_EFI
1367 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1369 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1370 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1372 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1374 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1375 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1379 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1380 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1383 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1384 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1390 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1392 int len
= GRUB_UINT_MAX
;
1393 const char *value
= NULL
;
1394 char name
[32] = {0};
1395 char plat
[32] = {0};
1396 char guidstr
[32] = {0};
1397 ventoy_guid guid
= VENTOY_GUID
;
1398 const char *fmt1
= NULL
;
1399 const char *fmt2
= NULL
;
1400 const char *fmt3
= NULL
;
1401 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1402 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1403 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1404 const char fmtcode
[]={
1405 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1406 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1407 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1408 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1409 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1410 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1413 grub_memset(name
, 0, sizeof(name
));
1414 puint
[0] = grub_swap_bytes32(0x56454e54);
1415 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1416 puint
[2] = grub_swap_bytes32(0x45525349);
1417 puint
[1] = grub_swap_bytes32(0x4f595f56);
1418 value
= ventoy_get_env(name
);
1420 grub_memset(name
, 0, sizeof(name
));
1421 puint
[1] = grub_swap_bytes32(0x5f544f50);
1422 puint
[0] = grub_swap_bytes32(0x56544c45);
1423 fmt1
= ventoy_get_env(name
);
1429 grub_memset(name
, 0, sizeof(name
));
1430 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1431 puint
[0] = grub_swap_bytes32(0x56544c45);
1432 fmt2
= ventoy_get_env(name
);
1434 grub_memset(name
, 0, sizeof(name
));
1435 puint
[1] = grub_swap_bytes32(0x5f434c52);
1436 puint
[0] = grub_swap_bytes32(0x56544c45);
1437 fmt3
= ventoy_get_env(name
);
1439 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1441 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1443 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1444 #pragma GCC diagnostic push
1445 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1446 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1447 fmt1
? fmt1
: fmtdata
,
1448 fmt2
? fmt2
: fmtdata
+ 4,
1449 value
? value
: "", plat
, guidstr
,
1450 fmt3
? fmt3
: fmtdata
+ 6);
1451 #pragma GCC diagnostic pop
1453 grub_memset(name
, 0, sizeof(name
));
1454 puint
[0] = grub_swap_bytes32(0x76746f79);
1455 puint
[2] = grub_swap_bytes32(0x656e7365);
1456 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1457 ventoy_set_env(name
, guidstr
);
1462 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1466 grub_uint8_t md5
[16];
1470 grub_memset(input
, 0, sizeof(input
));
1472 grub_printf("Enter password: ");
1475 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1477 grub_password_get(input
, 128);
1478 if (grub_strcmp(pwd
->text
, input
) == 0)
1483 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1485 grub_password_get(input
, 128);
1486 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1487 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1492 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1494 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1495 grub_password_get(input
+ offset
, 128);
1497 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1498 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1504 grub_printf("Invalid password!\n\n");
1511 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1513 img_info
*minimg
= NULL
;
1514 img_info
*img
= (img_info
*)(node
->firstiso
);
1516 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1518 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1533 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1535 img_iterator_node
*Minchild
= NULL
;
1536 img_iterator_node
*child
= node
->firstchild
;
1538 while (child
&& child
->parent
== node
)
1540 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1544 child
= child
->next
;
1549 Minchild
->select
= 1;
1555 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1558 img_info
*img
= NULL
;
1559 const char *dir_class
= NULL
;
1560 const char *dir_alias
= NULL
;
1561 img_iterator_node
*child
= NULL
;
1563 if (node
->isocnt
== 0 || node
->done
== 1)
1568 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1570 offset
= node
->parent
->dirlen
;
1573 if (node
== &g_img_iterator_head
)
1575 if (g_default_menu_mode
== 0)
1577 if (g_tree_view_menu_style
== 0)
1579 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1580 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1581 " echo 'return ...' \n"
1586 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1587 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1595 node
->dir
[node
->dirlen
- 1] = 0;
1596 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1599 dir_class
= "vtoydir";
1602 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1605 if (g_tree_view_menu_style
== 0)
1607 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1608 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1609 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1613 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1614 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1615 dir_alias
, dir_class
, node
->dir
+ offset
);
1620 dir_alias
= node
->dir
+ offset
;
1622 if (g_tree_view_menu_style
== 0)
1624 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1625 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1626 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1630 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1631 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1632 dir_alias
, dir_class
, node
->dir
+ offset
);
1636 if (g_tree_view_menu_style
== 0)
1638 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1639 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1640 " echo 'return ...' \n"
1645 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1646 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1652 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1654 ventoy_dynamic_tree_menu(child
);
1657 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1659 if (g_tree_view_menu_style
== 0)
1661 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1662 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1665 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1666 img
->unsupport
? "[***********] " : "",
1667 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1669 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1673 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1674 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1677 img
->unsupport
? "[***********] " : "",
1678 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1680 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1684 if (node
!= &g_img_iterator_head
)
1686 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1693 int ventoy_check_device_result(int ret
)
1697 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1698 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1699 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1703 grub_printf(VTOY_WARNING
"\n");
1704 grub_printf(VTOY_WARNING
"\n");
1705 grub_printf(VTOY_WARNING
"\n\n\n");
1707 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1708 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1710 grub_printf("\n\nWill exit after 10 seconds ...... ");
1718 int ventoy_check_device(grub_device_t dev
)
1722 grub_uint64_t offset
;
1727 struct grub_partition
*partition
;
1729 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1731 return ventoy_check_device_result(1 | 0x1000);
1734 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1735 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1736 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1738 #ifndef GRUB_MACHINE_EFI
1739 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1740 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1741 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1743 return ventoy_check_device_result(2 | 0x1000);
1752 /* We must have partition 2 */
1755 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1759 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1763 return ventoy_check_device_result(3 | 0x1000);
1766 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1768 grub_file_close(file
);
1769 return ventoy_check_device_result(4 | 0x1000);
1772 partition
= dev
->disk
->partition
;
1773 if (partition
->number
!= 0 || partition
->start
!= 2048)
1775 return ventoy_check_device_result(5);
1780 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
1782 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
1783 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
1784 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
1786 grub_file_close(file
);
1787 return ventoy_check_device_result(6);
1792 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1793 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1794 PartTbl
[1].SectorCount
!= 65536)
1796 grub_file_close(file
);
1797 return ventoy_check_device_result(6);
1803 offset
= partition
->start
+ partition
->len
;
1804 partition
= file
->device
->disk
->partition
;
1805 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1807 grub_file_close(file
);
1808 return ventoy_check_device_result(7);
1812 grub_file_close(file
);
1814 if (workaround
== 0)
1816 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1817 dev2
= grub_device_open(devname
);
1820 return ventoy_check_device_result(8);
1823 fs
= grub_fs_probe(dev2
);
1826 grub_device_close(dev2
);
1827 return ventoy_check_device_result(9);
1830 fs
->fs_label(dev2
, &label
);
1831 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1833 grub_device_close(dev2
);
1834 return ventoy_check_device_result(10);
1837 grub_device_close(dev2
);
1840 return ventoy_check_device_result(0);
1843 static int ventoy_set_default_menu(void)
1849 const char *strdata
= NULL
;
1850 img_info
*cur
= NULL
;
1851 img_info
*default_node
= NULL
;
1852 const char *default_image
= NULL
;
1854 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1855 if (default_image
&& default_image
[0] == '/')
1857 img_len
= grub_strlen(default_image
);
1859 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1861 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1873 if (0 == g_default_menu_mode
)
1875 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1879 def
= grub_strdup(default_image
);
1885 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1887 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1888 if (strdata
&& strdata
[0] == '/')
1890 pos
= def
+ grub_strlen(strdata
);
1901 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1904 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1908 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1916 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1920 grub_device_t dev
= NULL
;
1921 img_info
*cur
= NULL
;
1922 img_info
*tail
= NULL
;
1923 const char *strdata
= NULL
;
1924 char *device_name
= NULL
;
1926 img_iterator_node
*node
= NULL
;
1927 img_iterator_node
*tmp
= NULL
;
1933 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1936 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1938 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1941 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1942 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1944 g_filt_dot_underscore_file
= 1;
1947 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1948 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1950 g_sort_case_sensitive
= 1;
1953 device_name
= grub_file_get_device_name(args
[0]);
1959 g_enum_dev
= dev
= grub_device_open(device_name
);
1965 g_enum_fs
= fs
= grub_fs_probe(dev
);
1971 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1973 debug("unsupported fs:<%s>\n", fs
->name
);
1974 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1978 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1980 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1981 if (strdata
&& strdata
[0] == '1')
1983 g_default_menu_mode
= 1;
1986 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1988 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1990 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1991 if (strdata
&& strdata
[0] == '/')
1993 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1994 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1996 g_img_iterator_head
.dir
[len
++] = '/';
1998 g_img_iterator_head
.dirlen
= len
;
2002 g_img_iterator_head
.dirlen
= 1;
2003 grub_strcpy(g_img_iterator_head
.dir
, "/");
2006 g_img_iterator_head
.tail
= &tail
;
2008 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2010 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
2013 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2014 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2016 g_tree_view_menu_style
= 1;
2019 ventoy_set_default_menu();
2021 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2023 ventoy_dynamic_tree_menu(node
);
2027 node
= g_img_iterator_head
.next
;
2035 /* sort image list by image name */
2036 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2038 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2040 if (ventoy_cmp_img(cur
, tail
) > 0)
2042 ventoy_swap_img(cur
, tail
);
2047 if (g_default_menu_mode
== 1)
2049 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2050 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2051 " echo 'return ...' \n"
2055 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2057 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2058 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2061 cur
->unsupport
? "[***********] " : "",
2062 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2064 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2067 g_tree_script_buf
[g_tree_script_pos
] = 0;
2068 g_list_script_buf
[g_list_script_pos
] = 0;
2070 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2071 grub_env_set(args
[1], buf
);
2075 check_free(device_name
, grub_free
);
2076 check_free(dev
, grub_device_close
);
2078 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2082 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2084 img_info
*next
= NULL
;
2085 img_info
*cur
= g_ventoy_img_list
;
2098 g_ventoy_img_list
= NULL
;
2099 g_ventoy_img_count
= 0;
2101 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2104 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2107 img_info
*cur
= g_ventoy_img_list
;
2111 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2113 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2116 img_id
= grub_strtol(args
[0], NULL
, 10);
2117 if (img_id
>= g_ventoy_img_count
)
2119 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2122 debug("Find image %ld name \n", img_id
);
2124 while (cur
&& img_id
> 0)
2132 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2135 debug("image name is %s\n", cur
->name
);
2137 grub_env_set(args
[1], cur
->name
);
2139 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2142 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2147 const char *id
= NULL
;
2148 img_info
*cur
= g_ventoy_img_list
;
2152 if (argc
< 1 || argc
> 2)
2154 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2157 id
= grub_env_get("chosen");
2159 pos
= grub_strstr(id
, "VID_");
2162 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2166 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2171 if (img_id
== cur
->id
)
2180 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2183 grub_env_set(args
[0], cur
->path
);
2187 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2188 grub_env_set(args
[1], value
);
2191 g_svd_replace_offset
= 0;
2193 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2196 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2203 device_name
= grub_file_get_device_name(filename
);
2215 pos2
= grub_strstr(pos
, ",");
2218 pos2
= grub_strstr(pos
, ")");
2226 disk
= grub_disk_open(pos
);
2229 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2230 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2231 grub_disk_close(disk
);
2238 grub_free(device_name
);
2242 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2244 eltorito_descriptor desc
;
2246 grub_memset(&desc
, 0, sizeof(desc
));
2247 grub_file_seek(file
, 17 * 2048);
2248 grub_file_read(file
, &desc
, sizeof(desc
));
2250 if (desc
.type
!= 0 || desc
.version
!= 1)
2255 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2256 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2264 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2268 grub_uint8_t buf
[512];
2270 grub_file_seek(file
, sector
* 2048);
2271 grub_file_read(file
, buf
, sizeof(buf
));
2273 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2275 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2279 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2284 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2286 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2288 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2292 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2294 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2299 debug("%s does not contain efi eltorito\n", file
->name
);
2303 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2306 const char *fs
= NULL
;
2307 const char *cdprompt
= NULL
;
2309 grub_uint8_t chksum
= 0;
2312 disk
= file
->device
->disk
;
2313 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2315 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2316 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2317 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2319 pos
= grub_strstr(file
->name
, "/");
2325 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2327 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2329 param
->vtoy_img_size
= file
->size
;
2331 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2332 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2334 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2336 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2337 param
->vtoy_reserved
[4] = 0;
2338 if (g_ventoy_chain_type
== 1) /* Windows */
2340 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2341 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2343 param
->vtoy_reserved
[4] = 1;
2347 fs
= ventoy_get_env("ventoy_fs_probe");
2348 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2350 param
->vtoy_reserved
[3] = 1;
2353 /* calculate checksum */
2354 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2356 chksum
+= *((grub_uint8_t
*)param
+ i
);
2358 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2363 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2365 grub_uint32_t i
= 0;
2366 grub_uint64_t total
= 0;
2367 ventoy_img_chunk
*chunk
= NULL
;
2369 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2371 chunk
= chunklist
->chunk
+ i
;
2373 if (chunk
->disk_start_sector
<= start
)
2375 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2379 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2382 if (total
!= ((file
->size
+ 511) / 512))
2384 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2391 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2395 grub_uint32_t i
= 0;
2396 grub_uint32_t sector
= 0;
2397 grub_uint32_t count
= 0;
2398 grub_off_t size
= 0;
2399 grub_off_t read
= 0;
2401 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2402 if (fs_type
== ventoy_fs_exfat
)
2404 grub_fat_get_file_chunk(start
, file
, chunklist
);
2406 else if (fs_type
== ventoy_fs_ext
)
2408 grub_ext_get_file_chunk(start
, file
, chunklist
);
2412 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2413 file
->read_hook_data
= chunklist
;
2415 for (size
= file
->size
; size
> 0; size
-= read
)
2417 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2418 grub_file_read(file
, NULL
, read
);
2421 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2423 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2424 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2427 if (ventoy_fs_udf
== fs_type
)
2429 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2431 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2432 chunklist
->chunk
[i
].img_start_sector
= sector
;
2433 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2439 len
= (int)grub_strlen(file
->name
);
2440 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2441 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2442 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2443 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2445 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2447 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2457 chunklist
->chunk
[i
].img_start_sector
= sector
;
2458 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2466 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2470 grub_disk_addr_t start
;
2475 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2478 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2481 g_conf_replace_node
= NULL
;
2482 g_conf_replace_offset
= 0;
2484 if (g_img_chunk_list
.chunk
)
2486 grub_free(g_img_chunk_list
.chunk
);
2489 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2491 grub_file_close(file
);
2492 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2495 /* get image chunk data */
2496 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2497 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2498 if (NULL
== g_img_chunk_list
.chunk
)
2500 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2503 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2504 g_img_chunk_list
.cur_chunk
= 0;
2506 start
= file
->device
->disk
->partition
->start
;
2508 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2510 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2511 grub_file_close(file
);
2515 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2518 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2519 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2522 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2524 grub_uint64_t offset
= 0;
2525 grub_uint32_t align
= 0;
2526 grub_file_t file
= NULL
;
2527 conf_replace
*node
= NULL
;
2533 debug("select conf replace argc:%d\n", argc
);
2540 node
= ventoy_plugin_find_conf_replace(args
[1]);
2543 debug("Conf replace not found for %s\n", args
[1]);
2547 debug("Find conf replace for %s\n", args
[1]);
2549 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2552 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2556 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2557 grub_file_close(file
);
2559 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2562 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2566 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2568 if (align
> vtoy_max_replace_file_size
)
2570 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2574 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2575 g_conf_replace_new_len
= (int)file
->size
;
2576 g_conf_replace_new_len_align
= align
;
2578 g_conf_replace_node
= node
;
2579 g_conf_replace_offset
= offset
+ 2;
2581 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2586 grub_file_close(file
);
2588 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2591 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2596 char configfile
[128];
2597 install_template
*node
= NULL
;
2603 debug("select auto installation argc:%d\n", argc
);
2610 node
= ventoy_plugin_find_install_template(args
[0]);
2613 debug("Auto install template not found for %s\n", args
[0]);
2617 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2619 node
->cursel
= node
->autosel
- 1;
2620 debug("Auto install template auto select %d\n", node
->autosel
);
2624 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2630 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2631 " echo %s\n}\n", "123");
2633 for (i
= 0; i
< node
->templatenum
; i
++)
2635 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2637 node
->templatepath
[i
].path
);
2640 g_ventoy_menu_esc
= 1;
2641 g_ventoy_suppress_esc
= 1;
2643 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2644 grub_script_execute_sourcecode(configfile
);
2646 g_ventoy_menu_esc
= 0;
2647 g_ventoy_suppress_esc
= 0;
2651 node
->cursel
= g_ventoy_last_entry
- 1;
2653 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2656 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2661 char configfile
[128];
2662 persistence_config
*node
;
2668 debug("select persistence argc:%d\n", argc
);
2675 node
= ventoy_plugin_find_persistent(args
[0]);
2678 debug("Persistence image not found for %s\n", args
[0]);
2682 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2684 node
->cursel
= node
->autosel
- 1;
2685 debug("Persistence image auto select %d\n", node
->autosel
);
2689 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2695 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2696 " echo %s\n}\n", "123");
2698 for (i
= 0; i
< node
->backendnum
; i
++)
2700 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2702 node
->backendpath
[i
].path
);
2706 g_ventoy_menu_esc
= 1;
2707 g_ventoy_suppress_esc
= 1;
2709 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2710 grub_script_execute_sourcecode(configfile
);
2712 g_ventoy_menu_esc
= 0;
2713 g_ventoy_suppress_esc
= 0;
2717 node
->cursel
= g_ventoy_last_entry
- 1;
2719 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2722 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2725 ventoy_img_chunk
*cur
;
2731 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2733 cur
= g_img_chunk_list
.chunk
+ i
;
2734 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2735 cur
->img_start_sector
, cur
->img_end_sector
,
2736 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2740 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2743 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2747 ventoy_img_chunk_list chunklist
;
2752 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2755 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2758 /* get image chunk data */
2759 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2760 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2761 if (NULL
== chunklist
.chunk
)
2763 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2766 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2767 chunklist
.cur_chunk
= 0;
2769 ventoy_get_block_list(file
, &chunklist
, 0);
2771 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2773 grub_printf("########## UNSUPPORTED ###############\n");
2776 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2778 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2780 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2781 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2784 grub_printf("\n==================================\n");
2786 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2788 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2789 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2790 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2791 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2792 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2796 grub_free(chunklist
.chunk
);
2797 grub_file_close(file
);
2799 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2802 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2805 ventoy_grub_param_file_replace
*replace
= NULL
;
2813 replace
= &(g_grub_param
->file_replace
);
2814 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2816 replace
->old_name_cnt
= 0;
2817 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2819 replace
->old_name_cnt
++;
2820 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2823 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2826 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2829 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2837 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2838 grub_printf("%s", g_list_script_buf
);
2842 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2843 grub_printf("%s", g_tree_script_buf
);
2849 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2851 img_info
*cur
= g_ventoy_img_list
;
2859 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2860 grub_printf("name:<%s>\n\n", cur
->name
);
2867 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2873 ventoy_plugin_dump_injection();
2878 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2884 ventoy_plugin_dump_auto_install();
2889 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2895 ventoy_plugin_dump_persistence();
2900 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2911 if (args
[0][0] == '0')
2913 return g_ventoy_memdisk_mode
? 0 : 1;
2915 else if (args
[0][0] == '1')
2917 return g_ventoy_iso_raw
? 0 : 1;
2919 else if (args
[0][0] == '2')
2921 return g_ventoy_iso_uefi_drv
? 0 : 1;
2927 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2929 static int configfile_mode
= 0;
2930 char memfile
[128] = {0};
2937 * args[0]: 0:normal 1:configfile
2938 * args[1]: 0:list_buf 1:tree_buf
2943 debug("Invalid argc %d\n", argc
);
2947 if (args
[0][0] == '0')
2949 if (args
[1][0] == '0')
2951 grub_script_execute_sourcecode(g_list_script_buf
);
2955 grub_script_execute_sourcecode(g_tree_script_buf
);
2960 if (configfile_mode
)
2962 debug("Now already in F3 mode %d\n", configfile_mode
);
2966 if (args
[1][0] == '0')
2968 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2969 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2973 g_ventoy_last_entry
= -1;
2974 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2975 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2978 configfile_mode
= 1;
2979 grub_script_execute_sourcecode(memfile
);
2980 configfile_mode
= 0;
2986 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2997 g_ventoy_case_insensitive
= 1;
2998 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2999 g_ventoy_case_insensitive
= 0;
3005 grub_file_close(file
);
3011 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3016 const char *isopath
= NULL
;
3018 ventoy_mbr_head mbr
;
3025 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3028 isopath
= grub_env_get("vtoy_iso_part");
3031 debug("isopath is null %p\n", isopath
);
3035 debug("isopath is %s\n", isopath
);
3037 for (id
= 0; id
< 30 && (find
== 0); id
++)
3039 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3040 if (grub_strstr(isopath
, hdname
))
3042 debug("skip %s ...\n", hdname
);
3046 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3048 disk
= grub_disk_open(hdname
);
3051 debug("%s not exist\n", hdname
);
3055 grub_memset(&mbr
, 0, sizeof(mbr
));
3056 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3058 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3060 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3061 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3064 grub_env_set(args
[0], hdname
);
3068 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3072 debug("read %s failed\n", hdname
);
3075 grub_disk_close(disk
);
3081 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3092 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3095 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3098 debug("failed to open file %s\n", args
[0]);
3102 buf
= grub_malloc(len
);
3109 grub_file_read(file
, buf
, len
- 1);
3111 ventoy_get_line(buf
);
3112 ventoy_set_env(args
[1], buf
);
3116 grub_check_free(buf
);
3117 grub_file_close(file
);
3122 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3127 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3128 "0 %llu linear /dev/ventoy %llu\n",
3129 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3134 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3136 char *device_name
= NULL
;
3137 grub_device_t dev
= NULL
;
3142 g_part_list_pos
= 0;
3143 grub_env_unset("vtoy_img_part_file");
3150 device_name
= grub_file_get_device_name(args
[0]);
3153 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3157 dev
= grub_device_open(device_name
);
3160 debug("grub_device_open failed, %s\n", device_name
);
3164 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3166 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3167 grub_env_set("vtoy_img_part_file", buf
);
3171 check_free(device_name
, grub_free
);
3172 check_free(dev
, grub_device_close
);
3178 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3189 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3192 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3195 debug("failed to open file %s\n", args
[0]);
3199 buf
= grub_malloc(file
->size
+ 1);
3205 buf
[file
->size
] = 0;
3206 grub_file_read(file
, buf
, file
->size
);
3208 if (grub_strstr(buf
, args
[1]))
3215 grub_check_free(buf
);
3216 grub_file_close(file
);
3221 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3226 ventoy_iso9660_vd pvd
;
3233 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3236 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3239 debug("failed to open file %s\n", args
[0]);
3243 grub_file_seek(file
, 16 * 2048);
3244 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3245 if (len
!= sizeof(pvd
))
3247 debug("failed to read pvd %d\n", len
);
3251 grub_memset(buf
, 0, sizeof(buf
));
3252 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3253 ventoy_set_env(args
[1], buf
);
3255 grub_memset(buf
, 0, sizeof(buf
));
3256 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3257 ventoy_set_env(args
[2], buf
);
3260 grub_file_close(file
);
3265 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3276 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3279 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3282 debug("failed to open file %s\n", args
[0]);
3286 grub_memset(buf
, 0, sizeof(buf
));
3287 grub_file_seek(file
, 16 * 2048 + 813);
3288 len
= (int)grub_file_read(file
, buf
, 17);
3291 debug("failed to read create date %d\n", len
);
3295 ventoy_set_env(args
[1], buf
);
3298 grub_file_close(file
);
3303 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3309 ventoy_env_hook_root(1);
3314 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3320 ventoy_env_hook_root(0);
3325 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3332 int image_sector_size
;
3334 ventoy_chain_head
*chain
;
3335 ventoy_img_chunk
*chunk
;
3336 ventoy_os_param
*osparam
;
3337 ventoy_image_location
*location
;
3338 ventoy_image_disk_region
*region
;
3339 struct grub_acpi_table_header
*acpi
;
3348 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3350 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3356 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3358 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3360 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3364 img_chunk_num
= chain
->img_chunk_num
;
3366 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3367 datalen
= sizeof(ventoy_os_param
) + loclen
;
3369 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3370 acpi
= grub_zalloc(buflen
);
3376 /* Step1: Fill acpi table header */
3377 grub_memcpy(acpi
->signature
, "VTOY", 4);
3378 acpi
->length
= buflen
;
3380 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3381 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3383 acpi
->creator_id
[0] = 1;
3384 acpi
->creator_rev
= 1;
3386 /* Step2: Fill data */
3387 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3388 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3389 osparam
->vtoy_img_location_addr
= 0;
3390 osparam
->vtoy_img_location_len
= loclen
;
3391 osparam
->chksum
= 0;
3392 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3394 location
= (ventoy_image_location
*)(osparam
+ 1);
3395 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3396 location
->image_sector_size
= image_sector_size
;
3397 location
->disk_sector_size
= chain
->disk_sector_size
;
3398 location
->region_count
= img_chunk_num
;
3400 region
= location
->regions
;
3401 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3402 if (512 == image_sector_size
)
3404 for (i
= 0; i
< img_chunk_num
; i
++)
3406 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3407 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3408 region
->disk_start_sector
= chunk
->disk_start_sector
;
3415 for (i
= 0; i
< img_chunk_num
; i
++)
3417 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3418 region
->image_start_sector
= chunk
->img_start_sector
;
3419 region
->disk_start_sector
= chunk
->disk_start_sector
;
3425 /* Step3: Fill acpi checksum */
3427 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3429 /* load acpi table */
3430 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3431 grub_script_execute_sourcecode(cmd
);
3435 VENTOY_CMD_RETURN(0);
3438 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3444 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3445 g_ventoy_last_entry
= -1;
3450 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3456 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3461 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3463 grub_uint64_t sectors
;
3465 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3467 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3471 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3474 return sectors
* 512;
3477 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3479 const char *pos
= filename
+ 1;
3487 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3489 grub_strncpy((char *)data
, filename
, 128);
3500 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3503 char *device_name
= NULL
;
3504 grub_device_t dev
= NULL
;
3505 grub_fs_t fs
= NULL
;
3506 char buf
[128] = {0};
3512 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3516 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3518 device_name
= grub_file_get_device_name(args
[0]);
3521 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3525 dev
= grub_device_open(device_name
);
3528 debug("grub_device_open failed, %s\n", device_name
);
3532 fs
= grub_fs_probe(dev
);
3535 debug("grub_fs_probe failed, %s\n", device_name
);
3539 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3543 ventoy_set_env(args
[2], buf
);
3550 check_free(device_name
, grub_free
);
3551 check_free(dev
, grub_device_close
);
3556 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3566 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3567 if (!g_ventoy_part_info
)
3572 disk
= grub_disk_open(args
[0]);
3575 debug("Failed to open disk %s\n", args
[0]);
3579 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3581 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3582 grub_disk_close(disk
);
3584 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3585 dev
= grub_device_open(name
);
3588 /* make sure that we are running in a correct Ventoy device */
3589 ret
= ventoy_check_device(dev
);
3590 grub_device_close(dev
);
3601 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3604 grub_uint8_t zeroguid
[16] = {0};
3609 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3612 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3614 if (id
>= 1 && id
<= 128)
3616 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3624 if (id
>= 1 && id
<= 4)
3626 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3636 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3639 char *device_name
= NULL
;
3640 grub_device_t dev
= NULL
;
3641 grub_fs_t fs
= NULL
;
3648 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3652 device_name
= grub_file_get_device_name(args
[0]);
3655 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3659 dev
= grub_device_open(device_name
);
3662 debug("grub_device_open failed, %s\n", device_name
);
3666 fs
= grub_fs_probe(dev
);
3669 debug("grub_fs_probe failed, %s\n", device_name
);
3673 fs
->fs_label(dev
, &label
);
3676 ventoy_set_env(args
[1], label
);
3684 check_free(device_name
, grub_free
);
3685 check_free(dev
, grub_device_close
);
3690 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3694 grub_snprintf((char *)data
, 256, "%s", filename
);
3702 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3705 char *device_name
= NULL
;
3706 grub_device_t dev
= NULL
;
3707 grub_fs_t fs
= NULL
;
3708 char name
[256] ={0};
3714 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3718 device_name
= grub_file_get_device_name(args
[0]);
3721 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3725 dev
= grub_device_open(device_name
);
3728 debug("grub_device_open failed, %s\n", device_name
);
3732 fs
= grub_fs_probe(dev
);
3735 debug("grub_fs_probe failed, %s\n", device_name
);
3739 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3742 ventoy_set_env(args
[2], name
);
3749 check_free(device_name
, grub_free
);
3750 check_free(dev
, grub_device_close
);
3755 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3765 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3769 for (pos
= args
[0]; *pos
; pos
++)
3783 grub_env_set(args
[1], args
[0]);
3793 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3795 struct grub_video_mode_info info
;
3802 if (!g_video_mode_list
)
3804 ventoy_enum_video_mode();
3807 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3809 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3813 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3816 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3818 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3819 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3821 VENTOY_CMD_RETURN(0);
3824 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3826 struct grub_video_mode_info info
;
3833 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3835 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3839 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3842 grub_env_set(args
[0], buf
);
3844 VENTOY_CMD_RETURN(0);
3847 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3855 if (!g_video_mode_list
)
3860 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3861 if (id
< g_video_mode_num
)
3863 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3864 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3867 grub_env_set(args
[1], buf
);
3869 VENTOY_CMD_RETURN(0);
3872 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3874 grub_uint64_t size
= 0;
3877 char fullpath
[256] = {0};
3880 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3883 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3886 debug("grub_file_open failed <%s>\n", fullpath
);
3892 grub_file_close(file
);
3896 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3900 char fullpath
[256] = {0};
3903 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3906 file
= grub_file_open(fullpath
, type
);
3909 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3916 int ventoy_is_file_exist(const char *fmt
, ...)
3921 char buf
[256] = {0};
3923 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3927 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3930 grub_strncpy(pos
+ len
, "\" ]", 3);
3932 debug("script exec %s\n", buf
);
3934 if (0 == grub_script_execute_sourcecode(buf
))
3942 int ventoy_is_dir_exist(const char *fmt
, ...)
3947 char buf
[256] = {0};
3949 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
3953 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3956 grub_strncpy(pos
+ len
, "\" ]", 3);
3958 debug("script exec %s\n", buf
);
3960 if (0 == grub_script_execute_sourcecode(buf
))
3968 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
3971 grub_uint8_t
*outbuf
;
3972 grub_uint8_t gzHdr
[10] =
3974 0x1F, 0x8B, /* magic */
3977 0,0,0,0, /* mtime */
3982 grub_memset(&s
, 0, sizeof(mz_stream
));
3984 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
3986 outbuf
= (grub_uint8_t
*)mem_out
;
3988 mem_out_len
-= sizeof(gzHdr
) + 8;
3989 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
3990 outbuf
+= sizeof(gzHdr
);
3992 s
.avail_in
= mem_in_len
;
3995 s
.avail_out
= mem_out_len
;
3996 s
.next_out
= outbuf
;
3998 mz_deflate(&s
, MZ_FINISH
);
4002 outbuf
+= s
.total_out
;
4003 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
4004 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
4006 return s
.total_out
+ sizeof(gzHdr
) + 8;
4009 static int ventoy_env_init(void)
4013 grub_env_set("vtdebug_flag", "");
4015 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4016 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4017 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4018 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4020 ventoy_filt_register(0, ventoy_wrapper_open
);
4022 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4025 g_grub_param
->grub_env_get
= grub_env_get
;
4026 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4027 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4028 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4029 grub_env_set("env_param", buf
);
4030 grub_env_set("ventoy_env_param", buf
);
4031 grub_env_export("ventoy_env_param");
4037 static cmd_para ventoy_cmds
[] =
4039 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4040 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4041 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4042 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4043 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4044 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4045 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4046 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4047 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4048 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4049 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4050 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4051 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4052 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4053 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4054 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4055 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4056 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4057 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4058 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4060 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4061 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4062 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4063 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4064 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4065 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4066 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4068 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4069 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4070 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4071 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4072 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4073 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4074 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4075 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4078 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4079 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4080 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4081 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4082 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4083 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4084 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4085 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4086 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4087 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4088 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4090 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4091 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4092 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4093 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4094 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4095 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4097 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4098 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4099 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4100 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4101 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4102 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4103 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4104 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4105 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4106 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4108 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4109 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4110 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4111 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4112 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4113 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4114 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4115 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4117 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4118 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4119 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4122 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4123 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4124 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4126 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4127 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4128 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4131 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4132 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4133 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4134 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4135 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4136 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4137 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4138 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4139 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4140 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4142 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4143 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4144 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4150 GRUB_MOD_INIT(ventoy
)
4153 cmd_para
*cur
= NULL
;
4157 ventoy_arch_mode_init();
4159 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4161 cur
= ventoy_cmds
+ i
;
4162 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4163 cur
->summary
, cur
->description
, cur
->parser
);
4167 GRUB_MOD_FINI(ventoy
)
4171 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4173 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);