1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/misc.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
36 #include <grub/misc.h>
37 #include <grub/kernel.h>
38 #ifdef GRUB_MACHINE_EFI
39 #include <grub/efi/efi.h>
41 #include <grub/time.h>
42 #include <grub/video.h>
43 #include <grub/acpi.h>
44 #include <grub/charset.h>
45 #include <grub/crypto.h>
46 #include <grub/lib/crc.h>
47 #include <grub/ventoy.h>
48 #include "ventoy_def.h"
51 GRUB_MOD_LICENSE ("GPLv3+");
53 int g_ventoy_debug
= 0;
54 static int g_efi_os
= 0xFF;
55 initrd_info
*g_initrd_img_list
= NULL
;
56 initrd_info
*g_initrd_img_tail
= NULL
;
57 int g_initrd_img_count
= 0;
58 int g_valid_initrd_count
= 0;
59 int g_default_menu_mode
= 0;
60 int g_filt_dot_underscore_file
= 0;
61 int g_sort_case_sensitive
= 0;
62 int g_tree_view_menu_style
= 0;
63 static grub_file_t g_old_file
;
64 static int g_ventoy_last_entry_back
;
65 static grub_uint32_t g_ventoy_plat_data
;
68 char g_img_swap_tmp_buf
[1024];
69 img_info g_img_swap_tmp
;
70 img_info
*g_ventoy_img_list
= NULL
;
72 int g_ventoy_img_count
= 0;
74 grub_device_t g_enum_dev
= NULL
;
75 grub_fs_t g_enum_fs
= NULL
;
76 img_iterator_node g_img_iterator_head
;
77 img_iterator_node
*g_img_iterator_tail
= NULL
;
79 grub_uint8_t g_ventoy_break_level
= 0;
80 grub_uint8_t g_ventoy_debug_level
= 0;
81 grub_uint8_t g_ventoy_chain_type
= 0;
83 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
84 grub_uint32_t g_ventoy_cpio_size
= 0;
85 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
86 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
88 int g_plugin_image_list
= 0;
90 ventoy_grub_param
*g_grub_param
= NULL
;
92 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
94 ventoy_img_chunk_list g_img_chunk_list
;
96 int g_wimboot_enable
= 0;
97 ventoy_img_chunk_list g_wimiso_chunk_list
;
98 char *g_wimiso_path
= NULL
;
100 int g_vhdboot_enable
= 0;
102 grub_uint64_t g_conf_replace_offset
= 0;
103 grub_uint64_t g_svd_replace_offset
= 0;
104 conf_replace
*g_conf_replace_node
= NULL
;
105 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
106 int g_conf_replace_new_len
= 0;
107 int g_conf_replace_new_len_align
= 0;
109 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
110 grub_uint64_t g_ventoy_disk_size
= 0;
112 static char *g_tree_script_buf
= NULL
;
113 static int g_tree_script_pos
= 0;
115 static char *g_list_script_buf
= NULL
;
116 static int g_list_script_pos
= 0;
118 static char *g_part_list_buf
= NULL
;
119 static int g_part_list_pos
= 0;
121 static int g_video_mode_max
= 0;
122 static int g_video_mode_num
= 0;
123 static ventoy_video_mode
*g_video_mode_list
= NULL
;
125 static const char *g_menu_class
[] =
127 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
130 static const char *g_menu_prefix
[] =
132 "iso", "wim", "efi", "img", "vhd", "vtoy"
135 void ventoy_debug(const char *fmt
, ...)
139 va_start (args
, fmt
);
140 grub_vprintf (fmt
, args
);
144 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
154 for (i
= 0; i
< 16; i
++)
156 grub_printf("%02x ", guid
[i
]);
161 int ventoy_is_efi_os(void)
165 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
171 static int ventoy_get_fs_type(const char *fs
)
175 return ventoy_fs_max
;
177 else if (grub_strncmp(fs
, "exfat", 5) == 0)
179 return ventoy_fs_exfat
;
181 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
183 return ventoy_fs_ntfs
;
185 else if (grub_strncmp(fs
, "ext", 3) == 0)
187 return ventoy_fs_ext
;
189 else if (grub_strncmp(fs
, "xfs", 3) == 0)
191 return ventoy_fs_xfs
;
193 else if (grub_strncmp(fs
, "udf", 3) == 0)
195 return ventoy_fs_udf
;
197 else if (grub_strncmp(fs
, "fat", 3) == 0)
199 return ventoy_fs_fat
;
202 return ventoy_fs_max
;
205 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
224 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
226 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
230 static grub_err_t
ventoy_fs_close(grub_file_t file
)
232 grub_file_close(g_old_file
);
233 grub_free(file
->data
);
241 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
247 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
252 for (i
= 0; i
< g_video_mode_num
; i
++)
254 if (g_video_mode_list
[i
].width
== info
->width
&&
255 g_video_mode_list
[i
].height
== info
->height
&&
256 g_video_mode_list
[i
].bpp
== info
->bpp
)
262 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
263 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
264 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
267 if (g_video_mode_num
== g_video_mode_max
)
269 g_video_mode_max
*= 2;
270 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
276 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
278 if (v1
->bpp
== v2
->bpp
)
280 if (v1
->width
== v2
->width
)
282 if (v1
->height
== v2
->height
)
288 return (v1
->height
< v2
->height
) ? -1 : 1;
293 return (v1
->width
< v2
->width
) ? -1 : 1;
298 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
302 static int ventoy_enum_video_mode(void)
305 grub_video_adapter_t adapter
;
306 grub_video_driver_id_t id
;
307 ventoy_video_mode mode
;
309 g_video_mode_num
= 0;
310 g_video_mode_max
= 1024;
311 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
312 if (!g_video_mode_list
)
317 #ifdef GRUB_MACHINE_PCBIOS
318 grub_dl_load ("vbe");
321 id
= grub_video_get_driver_id ();
323 FOR_VIDEO_ADAPTERS (adapter
)
325 if (!adapter
->iterate
||
326 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
327 adapter
->init() != GRUB_ERR_NONE
)))
332 adapter
->iterate(ventoy_video_hook
, NULL
);
334 if (adapter
->id
!= id
)
340 /* sort video mode */
341 for (i
= 0; i
< g_video_mode_num
; i
++)
342 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
344 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
346 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
347 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
348 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
352 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
355 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
359 static struct grub_fs vtoy_fs
=
364 .fs_read
= ventoy_fs_read
,
365 .fs_close
= ventoy_fs_close
,
375 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
381 file
->data
= grub_malloc(rawFile
->size
+ 4096);
387 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
388 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
390 g_old_file
= rawFile
;
392 file
->size
= rawFile
->size
+ len
;
393 file
->device
= rawFile
->device
;
395 file
->not_easily_seekable
= 1;
400 static int ventoy_check_decimal_var(const char *name
, long *value
)
402 const char *value_str
= NULL
;
404 value_str
= grub_env_get(name
);
405 if (NULL
== value_str
)
407 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
410 if (!ventoy_is_decimal(value_str
))
412 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
415 *value
= grub_strtol(value_str
, NULL
, 10);
417 return GRUB_ERR_NONE
;
420 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
424 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
427 if (0 == grub_strcmp(args
[0], "on"))
430 grub_env_set("vtdebug_flag", "debug");
435 grub_env_set("vtdebug_flag", "");
438 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
441 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
445 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
447 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
448 grub_printf(" level:\r\n");
449 grub_printf(" 01/11: busybox / (+cat log)\r\n");
450 grub_printf(" 02/12: initrd / (+cat log)\r\n");
451 grub_printf(" 03/13: hook / (+cat log)\r\n");
453 grub_printf(" debug:\r\n");
454 grub_printf(" 0: debug is off\r\n");
455 grub_printf(" 1: debug is on\r\n");
457 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
460 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
462 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
464 g_ventoy_debug_level
= 1;
467 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
470 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
479 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
482 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
514 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
519 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
521 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
524 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
529 value_long
+= grub_strtol(args
[1], NULL
, 10);
531 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
532 grub_env_set(args
[0], buf
);
534 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
537 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
552 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
555 debug("failed to open file <%s> for udf check\n", args
[0]);
559 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
561 grub_env_set(args
[1], buf
);
563 grub_file_close(file
);
569 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
577 g_wimboot_enable
= 0;
578 grub_check_free(g_wimiso_path
);
579 grub_check_free(g_wimiso_chunk_list
.chunk
);
581 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
587 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
588 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
589 if (NULL
== g_wimiso_chunk_list
.chunk
)
591 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
594 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
595 g_wimiso_chunk_list
.cur_chunk
= 0;
597 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
599 g_wimboot_enable
= 1;
600 g_wimiso_path
= grub_strdup(args
[0]);
602 grub_file_close(file
);
607 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
613 grub_uint32_t offset
;
615 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
618 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
622 len
= (int)file
->size
;
624 data
= (char *)grub_malloc(file
->size
);
630 grub_file_read(file
, data
, file
->size
);
631 grub_file_close(file
);
633 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
634 grub_script_execute_sourcecode(exec
);
636 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
637 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
638 grub_file_close(file
);
640 grub_script_execute_sourcecode("loopback -d efiboot");
644 *direntoff
= offset
+ 2;
649 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
659 ventoy_iso9660_override
*dirent
;
668 totlen
= sizeof(ventoy_chain_head
);
670 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
672 debug("failed to load efiboot template %d\n", len
);
678 debug("efiboot template len:%d offset:%d\n", len
, offset
);
680 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
683 debug("failed to open file <%s>\n", args
[0]);
687 totlen
+= ventoy_align_2k(file
->size
);
689 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
690 dirent
->first_sector
= len
/ 2048;
691 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
692 dirent
->size
= (grub_uint32_t
)file
->size
;
693 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
695 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
697 #ifdef GRUB_MACHINE_EFI
698 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
700 data
= (char *)grub_malloc(totlen
);
703 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
705 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
706 grub_check_free(buf
);
708 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
709 grub_file_close(file
);
711 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
712 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
713 grub_env_set(name
, value
);
715 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
716 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
717 grub_env_set(name
, value
);
722 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
739 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
742 debug("failed to open file <%s>\n", args
[0]);
746 #ifdef GRUB_MACHINE_EFI
747 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
749 buf
= (char *)grub_malloc(file
->size
);
752 grub_file_read(file
, buf
, file
->size
);
754 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
755 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
756 grub_env_set(name
, value
);
758 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
759 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
760 grub_env_set(name
, value
);
762 grub_file_close(file
);
768 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
786 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
789 debug("failed to open file <%s> for udf check\n", args
[0]);
793 headlen
= sizeof(ventoy_chain_head
);
795 #ifdef GRUB_MACHINE_EFI
796 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
798 buf
= (char *)grub_malloc(headlen
+ file
->size
);
801 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
803 grub_file_read(file
, buf
+ headlen
, file
->size
);
805 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
806 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
807 grub_env_set(name
, value
);
809 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
810 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
811 grub_env_set(name
, value
);
813 grub_file_close(file
);
819 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
828 if (args
[0][0] == '1')
830 grub_iso9660_set_nojoliet(1);
834 grub_iso9660_set_nojoliet(0);
840 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
845 grub_uint8_t buf
[32];
856 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
859 debug("failed to open file <%s> for udf check\n", args
[0]);
863 for (i
= 16; i
< 32; i
++)
865 grub_file_seek(file
, i
* 2048);
866 grub_file_read(file
, buf
, sizeof(buf
));
874 grub_file_seek(file
, i
* 2048);
875 grub_file_read(file
, buf
, sizeof(buf
));
877 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
880 grub_file_seek(file
, i
* 2048);
881 grub_file_read(file
, buf
, sizeof(buf
));
883 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
884 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
890 grub_file_close(file
);
892 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
897 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
899 long value_long1
= 0;
900 long value_long2
= 0;
902 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
904 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
907 value_long1
= grub_strtol(args
[0], NULL
, 10);
908 value_long2
= grub_strtol(args
[2], NULL
, 10);
910 if (0 == grub_strcmp(args
[1], "eq"))
912 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
914 else if (0 == grub_strcmp(args
[1], "ne"))
916 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
918 else if (0 == grub_strcmp(args
[1], "gt"))
920 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
922 else if (0 == grub_strcmp(args
[1], "lt"))
924 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
926 else if (0 == grub_strcmp(args
[1], "ge"))
928 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
930 else if (0 == grub_strcmp(args
[1], "le"))
932 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
936 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
942 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
949 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
952 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
953 pos
= grub_strstr(buf
, ",");
959 grub_env_set(args
[1], buf
);
961 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
964 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
970 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
976 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
979 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
981 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
982 if (0 == grub_script_execute_sourcecode(buf
))
984 debug("file %s exist, ventoy_compatible YES\n", buf
);
985 grub_env_set("ventoy_compatible", "YES");
986 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
990 debug("file %s NOT exist\n", buf
);
994 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
995 pos
= grub_strstr(buf
, ")");
1001 disk
= grub_disk_open(buf
);
1004 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1005 grub_disk_close(disk
);
1007 g_img_swap_tmp_buf
[703] = 0;
1008 for (i
= 318; i
< 703; i
++)
1010 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1011 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1013 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1014 grub_env_set("ventoy_compatible", "YES");
1015 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1021 debug("failed to open disk <%s>\n", buf
);
1024 grub_env_set("ventoy_compatible", "NO");
1025 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1028 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1034 if (g_plugin_image_list
)
1036 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1039 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1044 if (0 == g_sort_case_sensitive
)
1046 if (grub_islower(c1
))
1048 c1
= c1
- 'a' + 'A';
1051 if (grub_islower(c2
))
1053 c2
= c2
- 'a' + 'A';
1066 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1072 if (g_plugin_image_list
)
1074 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1077 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1082 if (0 == g_sort_case_sensitive
)
1084 if (grub_islower(c1
))
1086 c1
= c1
- 'a' + 'A';
1089 if (grub_islower(c2
))
1091 c2
= c2
- 'a' + 'A';
1104 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1106 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1108 grub_memcpy(img1
, img2
, sizeof(img_info
));
1109 img1
->next
= g_img_swap_tmp
.next
;
1110 img1
->prev
= g_img_swap_tmp
.prev
;
1112 g_img_swap_tmp
.next
= img2
->next
;
1113 g_img_swap_tmp
.prev
= img2
->prev
;
1114 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1117 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1121 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1129 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1133 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1143 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1152 img_iterator_node
*tmp
;
1153 img_iterator_node
*new_node
;
1154 img_iterator_node
*node
= (img_iterator_node
*)data
;
1156 len
= grub_strlen(filename
);
1160 if ((len
== 1 && filename
[0] == '.') ||
1161 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1166 if (!ventoy_img_name_valid(filename
, len
))
1171 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1176 if (g_plugin_image_list
)
1178 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1179 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1182 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1187 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1190 new_node
->plugin_list_index
= index
;
1191 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1193 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1196 debug("Directory %s ignored...\n", new_node
->dir
);
1197 grub_free(new_node
);
1201 new_node
->tail
= node
->tail
;
1203 new_node
->parent
= node
;
1204 if (!node
->firstchild
)
1206 node
->firstchild
= new_node
;
1209 if (g_img_iterator_tail
)
1211 g_img_iterator_tail
->next
= new_node
;
1212 g_img_iterator_tail
= new_node
;
1216 g_img_iterator_head
.next
= new_node
;
1217 g_img_iterator_tail
= new_node
;
1223 debug("Find a file %s\n", filename
);
1229 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1231 type
= img_type_iso
;
1233 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1235 type
= img_type_wim
;
1237 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1238 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1240 type
= img_type_vhd
;
1242 #ifdef GRUB_MACHINE_EFI
1243 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1245 type
= img_type_efi
;
1248 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1250 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1252 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1253 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1258 type
= img_type_img
;
1260 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1262 type
= img_type_vtoy
;
1269 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1274 if (g_plugin_image_list
)
1276 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1277 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1280 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1285 img
= grub_zalloc(sizeof(img_info
));
1289 img
->plugin_list_index
= index
;
1290 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1292 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1294 img
->size
= info
->size
;
1297 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1300 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1302 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1307 if (g_ventoy_img_list
)
1309 tail
= *(node
->tail
);
1315 g_ventoy_img_list
= img
;
1318 img
->id
= g_ventoy_img_count
;
1320 if (node
&& NULL
== node
->firstiso
)
1322 node
->firstiso
= img
;
1333 *((img_info
**)(node
->tail
)) = img
;
1334 g_ventoy_img_count
++;
1336 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1337 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1340 img
->class = g_menu_class
[type
];
1342 img
->menu_prefix
= g_menu_prefix
[type
];
1344 if (img_type_iso
== type
)
1346 if (ventoy_plugin_check_memdisk(img
->path
))
1348 img
->menu_prefix
= "miso";
1352 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1359 static int ventoy_arch_mode_init(void)
1361 #ifdef GRUB_MACHINE_EFI
1362 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
1364 g_ventoy_plat_data
= VTOY_PLAT_I386_UEFI
;
1365 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
1367 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
1369 g_ventoy_plat_data
= VTOY_PLAT_ARM64_UEFI
;
1370 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
1374 g_ventoy_plat_data
= VTOY_PLAT_X86_64_UEFI
;
1375 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
1378 g_ventoy_plat_data
= VTOY_PLAT_X86_LEGACY
;
1379 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
1385 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1387 int len
= GRUB_UINT_MAX
;
1388 const char *value
= NULL
;
1389 char name
[32] = {0};
1390 char plat
[32] = {0};
1391 char guidstr
[32] = {0};
1392 ventoy_guid guid
= VENTOY_GUID
;
1393 const char *fmt1
= NULL
;
1394 const char *fmt2
= NULL
;
1395 const char *fmt3
= NULL
;
1396 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1397 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1398 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1399 const char fmtcode
[]={
1400 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1401 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1402 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1403 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1404 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1405 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1408 grub_memset(name
, 0, sizeof(name
));
1409 puint
[0] = grub_swap_bytes32(0x56454e54);
1410 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1411 puint
[2] = grub_swap_bytes32(0x45525349);
1412 puint
[1] = grub_swap_bytes32(0x4f595f56);
1413 value
= ventoy_get_env(name
);
1415 grub_memset(name
, 0, sizeof(name
));
1416 puint
[1] = grub_swap_bytes32(0x5f544f50);
1417 puint
[0] = grub_swap_bytes32(0x56544c45);
1418 fmt1
= ventoy_get_env(name
);
1424 grub_memset(name
, 0, sizeof(name
));
1425 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1426 puint
[0] = grub_swap_bytes32(0x56544c45);
1427 fmt2
= ventoy_get_env(name
);
1429 grub_memset(name
, 0, sizeof(name
));
1430 puint
[1] = grub_swap_bytes32(0x5f434c52);
1431 puint
[0] = grub_swap_bytes32(0x56544c45);
1432 fmt3
= ventoy_get_env(name
);
1434 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1436 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1438 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1439 #pragma GCC diagnostic push
1440 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1441 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1442 fmt1
? fmt1
: fmtdata
,
1443 fmt2
? fmt2
: fmtdata
+ 4,
1444 value
? value
: "", plat
, guidstr
,
1445 fmt3
? fmt3
: fmtdata
+ 6);
1446 #pragma GCC diagnostic pop
1448 grub_memset(name
, 0, sizeof(name
));
1449 puint
[0] = grub_swap_bytes32(0x76746f79);
1450 puint
[2] = grub_swap_bytes32(0x656e7365);
1451 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1452 ventoy_set_env(name
, guidstr
);
1457 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1461 grub_uint8_t md5
[16];
1465 grub_memset(input
, 0, sizeof(input
));
1467 grub_printf("Enter password: ");
1470 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1472 grub_password_get(input
, 128);
1473 if (grub_strcmp(pwd
->text
, input
) == 0)
1478 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1480 grub_password_get(input
, 128);
1481 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1482 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1487 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1489 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1490 grub_password_get(input
+ offset
, 128);
1492 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1493 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1499 grub_printf("Invalid password!\n\n");
1506 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1508 img_info
*minimg
= NULL
;
1509 img_info
*img
= (img_info
*)(node
->firstiso
);
1511 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1513 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1528 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1530 img_iterator_node
*Minchild
= NULL
;
1531 img_iterator_node
*child
= node
->firstchild
;
1533 while (child
&& child
->parent
== node
)
1535 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1539 child
= child
->next
;
1544 Minchild
->select
= 1;
1550 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1553 img_info
*img
= NULL
;
1554 const char *dir_class
= NULL
;
1555 const char *dir_alias
= NULL
;
1556 img_iterator_node
*child
= NULL
;
1558 if (node
->isocnt
== 0 || node
->done
== 1)
1563 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1565 offset
= node
->parent
->dirlen
;
1568 if (node
== &g_img_iterator_head
)
1570 if (g_default_menu_mode
== 0)
1572 if (g_tree_view_menu_style
== 0)
1574 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1575 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1576 " echo 'return ...' \n"
1581 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1582 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1590 node
->dir
[node
->dirlen
- 1] = 0;
1591 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1594 dir_class
= "vtoydir";
1597 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1600 if (g_tree_view_menu_style
== 0)
1602 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1603 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1604 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1608 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1609 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1610 dir_alias
, dir_class
, node
->dir
+ offset
);
1615 dir_alias
= node
->dir
+ offset
;
1617 if (g_tree_view_menu_style
== 0)
1619 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1620 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1621 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1625 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1626 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1627 dir_alias
, dir_class
, node
->dir
+ offset
);
1631 if (g_tree_view_menu_style
== 0)
1633 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1634 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1635 " echo 'return ...' \n"
1640 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1641 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1647 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1649 ventoy_dynamic_tree_menu(child
);
1652 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1654 if (g_tree_view_menu_style
== 0)
1656 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1657 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1660 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1661 img
->unsupport
? "[***********] " : "",
1662 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1664 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1668 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1669 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1672 img
->unsupport
? "[***********] " : "",
1673 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1675 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1679 if (node
!= &g_img_iterator_head
)
1681 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1688 int ventoy_check_device_result(int ret
)
1692 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1693 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1694 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1698 grub_printf(VTOY_WARNING
"\n");
1699 grub_printf(VTOY_WARNING
"\n");
1700 grub_printf(VTOY_WARNING
"\n\n\n");
1702 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1703 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1705 grub_printf("\n\nWill exit after 10 seconds ...... ");
1713 int ventoy_check_device(grub_device_t dev
)
1717 grub_uint64_t offset
;
1722 struct grub_partition
*partition
;
1724 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1726 return ventoy_check_device_result(1 | 0x1000);
1729 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1730 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1731 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1733 #ifndef GRUB_MACHINE_EFI
1734 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1735 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
1736 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1738 return ventoy_check_device_result(2 | 0x1000);
1747 /* We must have partition 2 */
1750 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
1754 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1758 return ventoy_check_device_result(3 | 0x1000);
1761 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1763 grub_file_close(file
);
1764 return ventoy_check_device_result(4 | 0x1000);
1767 partition
= dev
->disk
->partition
;
1768 if (partition
->number
!= 0 || partition
->start
!= 2048)
1770 return ventoy_check_device_result(5);
1775 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
1776 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
1777 PartTbl
[1].SectorCount
!= 65536)
1779 grub_file_close(file
);
1780 return ventoy_check_device_result(6);
1785 offset
= partition
->start
+ partition
->len
;
1786 partition
= file
->device
->disk
->partition
;
1787 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1789 grub_file_close(file
);
1790 return ventoy_check_device_result(7);
1794 grub_file_close(file
);
1796 if (workaround
== 0)
1798 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1799 dev2
= grub_device_open(devname
);
1802 return ventoy_check_device_result(8);
1805 fs
= grub_fs_probe(dev2
);
1808 grub_device_close(dev2
);
1809 return ventoy_check_device_result(9);
1812 fs
->fs_label(dev2
, &label
);
1813 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1815 grub_device_close(dev2
);
1816 return ventoy_check_device_result(10);
1819 grub_device_close(dev2
);
1822 return ventoy_check_device_result(0);
1825 static int ventoy_set_default_menu(void)
1831 const char *strdata
= NULL
;
1832 img_info
*cur
= NULL
;
1833 img_info
*default_node
= NULL
;
1834 const char *default_image
= NULL
;
1836 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1837 if (default_image
&& default_image
[0] == '/')
1839 img_len
= grub_strlen(default_image
);
1841 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1843 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1855 if (0 == g_default_menu_mode
)
1857 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1861 def
= grub_strdup(default_image
);
1867 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1869 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1870 if (strdata
&& strdata
[0] == '/')
1872 pos
= def
+ grub_strlen(strdata
);
1883 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1886 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1890 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1898 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1902 grub_device_t dev
= NULL
;
1903 img_info
*cur
= NULL
;
1904 img_info
*tail
= NULL
;
1905 const char *strdata
= NULL
;
1906 char *device_name
= NULL
;
1908 img_iterator_node
*node
= NULL
;
1909 img_iterator_node
*tmp
= NULL
;
1915 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1918 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1920 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1923 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1924 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1926 g_filt_dot_underscore_file
= 1;
1929 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1930 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1932 g_sort_case_sensitive
= 1;
1935 device_name
= grub_file_get_device_name(args
[0]);
1941 g_enum_dev
= dev
= grub_device_open(device_name
);
1947 g_enum_fs
= fs
= grub_fs_probe(dev
);
1953 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1955 debug("unsupported fs:<%s>\n", fs
->name
);
1956 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1960 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1962 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1963 if (strdata
&& strdata
[0] == '1')
1965 g_default_menu_mode
= 1;
1968 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1970 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1972 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1973 if (strdata
&& strdata
[0] == '/')
1975 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1976 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1978 g_img_iterator_head
.dir
[len
++] = '/';
1980 g_img_iterator_head
.dirlen
= len
;
1984 g_img_iterator_head
.dirlen
= 1;
1985 grub_strcpy(g_img_iterator_head
.dir
, "/");
1988 g_img_iterator_head
.tail
= &tail
;
1990 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1992 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1995 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1996 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1998 g_tree_view_menu_style
= 1;
2001 ventoy_set_default_menu();
2003 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2005 ventoy_dynamic_tree_menu(node
);
2009 node
= g_img_iterator_head
.next
;
2017 /* sort image list by image name */
2018 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2020 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
2022 if (ventoy_cmp_img(cur
, tail
) > 0)
2024 ventoy_swap_img(cur
, tail
);
2029 if (g_default_menu_mode
== 1)
2031 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2032 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2033 " echo 'return ...' \n"
2037 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2039 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2040 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
2043 cur
->unsupport
? "[***********] " : "",
2044 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
2046 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2049 g_tree_script_buf
[g_tree_script_pos
] = 0;
2050 g_list_script_buf
[g_list_script_pos
] = 0;
2052 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2053 grub_env_set(args
[1], buf
);
2057 check_free(device_name
, grub_free
);
2058 check_free(dev
, grub_device_close
);
2060 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2064 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2066 img_info
*next
= NULL
;
2067 img_info
*cur
= g_ventoy_img_list
;
2080 g_ventoy_img_list
= NULL
;
2081 g_ventoy_img_count
= 0;
2083 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2086 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2089 img_info
*cur
= g_ventoy_img_list
;
2093 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2095 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2098 img_id
= grub_strtol(args
[0], NULL
, 10);
2099 if (img_id
>= g_ventoy_img_count
)
2101 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2104 debug("Find image %ld name \n", img_id
);
2106 while (cur
&& img_id
> 0)
2114 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2117 debug("image name is %s\n", cur
->name
);
2119 grub_env_set(args
[1], cur
->name
);
2121 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2124 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2129 const char *id
= NULL
;
2130 img_info
*cur
= g_ventoy_img_list
;
2134 if (argc
< 1 || argc
> 2)
2136 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2139 id
= grub_env_get("chosen");
2141 pos
= grub_strstr(id
, "VID_");
2144 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2148 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2153 if (img_id
== cur
->id
)
2162 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2165 grub_env_set(args
[0], cur
->path
);
2169 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2170 grub_env_set(args
[1], value
);
2173 g_svd_replace_offset
= 0;
2175 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2178 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2185 device_name
= grub_file_get_device_name(filename
);
2197 pos2
= grub_strstr(pos
, ",");
2200 pos2
= grub_strstr(pos
, ")");
2208 disk
= grub_disk_open(pos
);
2211 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2212 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2213 grub_disk_close(disk
);
2220 grub_free(device_name
);
2224 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2226 eltorito_descriptor desc
;
2228 grub_memset(&desc
, 0, sizeof(desc
));
2229 grub_file_seek(file
, 17 * 2048);
2230 grub_file_read(file
, &desc
, sizeof(desc
));
2232 if (desc
.type
!= 0 || desc
.version
!= 1)
2237 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2238 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2246 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2250 grub_uint8_t buf
[512];
2252 grub_file_seek(file
, sector
* 2048);
2253 grub_file_read(file
, buf
, sizeof(buf
));
2255 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2257 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2261 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2266 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2268 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2270 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2274 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2276 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2281 debug("%s does not contain efi eltorito\n", file
->name
);
2285 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2288 const char *fs
= NULL
;
2289 const char *cdprompt
= NULL
;
2291 grub_uint8_t chksum
= 0;
2294 disk
= file
->device
->disk
;
2295 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2297 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2298 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2299 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2301 pos
= grub_strstr(file
->name
, "/");
2307 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2309 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2311 param
->vtoy_img_size
= file
->size
;
2313 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2314 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2316 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2318 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2319 param
->vtoy_reserved
[4] = 0;
2320 if (g_ventoy_chain_type
== 1) /* Windows */
2322 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2323 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2325 param
->vtoy_reserved
[4] = 1;
2329 fs
= ventoy_get_env("ventoy_fs_probe");
2330 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2332 param
->vtoy_reserved
[3] = 1;
2335 /* calculate checksum */
2336 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2338 chksum
+= *((grub_uint8_t
*)param
+ i
);
2340 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2345 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2347 grub_uint32_t i
= 0;
2348 grub_uint64_t total
= 0;
2349 ventoy_img_chunk
*chunk
= NULL
;
2351 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2353 chunk
= chunklist
->chunk
+ i
;
2355 if (chunk
->disk_start_sector
<= start
)
2357 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2361 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2364 if (total
!= ((file
->size
+ 511) / 512))
2366 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2373 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2377 grub_uint32_t i
= 0;
2378 grub_uint32_t sector
= 0;
2379 grub_uint32_t count
= 0;
2380 grub_off_t size
= 0;
2381 grub_off_t read
= 0;
2383 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2384 if (fs_type
== ventoy_fs_exfat
)
2386 grub_fat_get_file_chunk(start
, file
, chunklist
);
2388 else if (fs_type
== ventoy_fs_ext
)
2390 grub_ext_get_file_chunk(start
, file
, chunklist
);
2394 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2395 file
->read_hook_data
= chunklist
;
2397 for (size
= file
->size
; size
> 0; size
-= read
)
2399 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2400 grub_file_read(file
, NULL
, read
);
2403 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2405 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2406 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2409 if (ventoy_fs_udf
== fs_type
)
2411 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2413 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2414 chunklist
->chunk
[i
].img_start_sector
= sector
;
2415 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2421 len
= (int)grub_strlen(file
->name
);
2422 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2423 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2424 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2425 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2427 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2429 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2439 chunklist
->chunk
[i
].img_start_sector
= sector
;
2440 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2448 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2452 grub_disk_addr_t start
;
2457 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2460 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2463 g_conf_replace_node
= NULL
;
2464 g_conf_replace_offset
= 0;
2466 if (g_img_chunk_list
.chunk
)
2468 grub_free(g_img_chunk_list
.chunk
);
2471 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2473 grub_file_close(file
);
2474 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2477 /* get image chunk data */
2478 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2479 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2480 if (NULL
== g_img_chunk_list
.chunk
)
2482 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2485 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2486 g_img_chunk_list
.cur_chunk
= 0;
2488 start
= file
->device
->disk
->partition
->start
;
2490 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2492 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2493 grub_file_close(file
);
2497 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2500 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2501 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2504 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2506 grub_uint64_t offset
= 0;
2507 grub_uint32_t align
= 0;
2508 grub_file_t file
= NULL
;
2509 conf_replace
*node
= NULL
;
2515 debug("select conf replace argc:%d\n", argc
);
2522 node
= ventoy_plugin_find_conf_replace(args
[1]);
2525 debug("Conf replace not found for %s\n", args
[1]);
2529 debug("Find conf replace for %s\n", args
[1]);
2531 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2534 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2538 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2539 grub_file_close(file
);
2541 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2544 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2548 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2550 if (align
> vtoy_max_replace_file_size
)
2552 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2556 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2557 g_conf_replace_new_len
= (int)file
->size
;
2558 g_conf_replace_new_len_align
= align
;
2560 g_conf_replace_node
= node
;
2561 g_conf_replace_offset
= offset
+ 2;
2563 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2568 grub_file_close(file
);
2570 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2573 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2578 char configfile
[128];
2579 install_template
*node
= NULL
;
2585 debug("select auto installation argc:%d\n", argc
);
2592 node
= ventoy_plugin_find_install_template(args
[0]);
2595 debug("Auto install template not found for %s\n", args
[0]);
2599 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2601 node
->cursel
= node
->autosel
- 1;
2602 debug("Auto install template auto select %d\n", node
->autosel
);
2606 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2612 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2613 " echo %s\n}\n", "123");
2615 for (i
= 0; i
< node
->templatenum
; i
++)
2617 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2619 node
->templatepath
[i
].path
);
2622 g_ventoy_menu_esc
= 1;
2623 g_ventoy_suppress_esc
= 1;
2625 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2626 grub_script_execute_sourcecode(configfile
);
2628 g_ventoy_menu_esc
= 0;
2629 g_ventoy_suppress_esc
= 0;
2633 node
->cursel
= g_ventoy_last_entry
- 1;
2635 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2638 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2643 char configfile
[128];
2644 persistence_config
*node
;
2650 debug("select persistence argc:%d\n", argc
);
2657 node
= ventoy_plugin_find_persistent(args
[0]);
2660 debug("Persistence image not found for %s\n", args
[0]);
2664 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2666 node
->cursel
= node
->autosel
- 1;
2667 debug("Persistence image auto select %d\n", node
->autosel
);
2671 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2677 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2678 " echo %s\n}\n", "123");
2680 for (i
= 0; i
< node
->backendnum
; i
++)
2682 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2684 node
->backendpath
[i
].path
);
2688 g_ventoy_menu_esc
= 1;
2689 g_ventoy_suppress_esc
= 1;
2691 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2692 grub_script_execute_sourcecode(configfile
);
2694 g_ventoy_menu_esc
= 0;
2695 g_ventoy_suppress_esc
= 0;
2699 node
->cursel
= g_ventoy_last_entry
- 1;
2701 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2704 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2707 ventoy_img_chunk
*cur
;
2713 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2715 cur
= g_img_chunk_list
.chunk
+ i
;
2716 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2717 cur
->img_start_sector
, cur
->img_end_sector
,
2718 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2722 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2725 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2729 ventoy_img_chunk_list chunklist
;
2734 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2737 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2740 /* get image chunk data */
2741 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2742 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2743 if (NULL
== chunklist
.chunk
)
2745 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2748 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2749 chunklist
.cur_chunk
= 0;
2751 ventoy_get_block_list(file
, &chunklist
, 0);
2753 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2755 grub_printf("########## UNSUPPORTED ###############\n");
2758 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2760 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2762 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2763 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2766 grub_printf("\n==================================\n");
2768 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2770 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2771 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2772 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2773 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2774 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2778 grub_free(chunklist
.chunk
);
2779 grub_file_close(file
);
2781 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2784 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2787 ventoy_grub_param_file_replace
*replace
= NULL
;
2795 replace
= &(g_grub_param
->file_replace
);
2796 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2798 replace
->old_name_cnt
= 0;
2799 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2801 replace
->old_name_cnt
++;
2802 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2805 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2808 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2811 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2819 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2820 grub_printf("%s", g_list_script_buf
);
2824 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2825 grub_printf("%s", g_tree_script_buf
);
2831 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2833 img_info
*cur
= g_ventoy_img_list
;
2841 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2842 grub_printf("name:<%s>\n\n", cur
->name
);
2849 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2855 ventoy_plugin_dump_injection();
2860 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2866 ventoy_plugin_dump_auto_install();
2871 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2877 ventoy_plugin_dump_persistence();
2882 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2893 if (args
[0][0] == '0')
2895 return g_ventoy_memdisk_mode
? 0 : 1;
2897 else if (args
[0][0] == '1')
2899 return g_ventoy_iso_raw
? 0 : 1;
2901 else if (args
[0][0] == '2')
2903 return g_ventoy_iso_uefi_drv
? 0 : 1;
2909 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2911 static int configfile_mode
= 0;
2912 char memfile
[128] = {0};
2919 * args[0]: 0:normal 1:configfile
2920 * args[1]: 0:list_buf 1:tree_buf
2925 debug("Invalid argc %d\n", argc
);
2929 if (args
[0][0] == '0')
2931 if (args
[1][0] == '0')
2933 grub_script_execute_sourcecode(g_list_script_buf
);
2937 grub_script_execute_sourcecode(g_tree_script_buf
);
2942 if (configfile_mode
)
2944 debug("Now already in F3 mode %d\n", configfile_mode
);
2948 if (args
[1][0] == '0')
2950 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2951 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2955 g_ventoy_last_entry
= -1;
2956 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2957 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2960 configfile_mode
= 1;
2961 grub_script_execute_sourcecode(memfile
);
2962 configfile_mode
= 0;
2968 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2979 g_ventoy_case_insensitive
= 1;
2980 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2981 g_ventoy_case_insensitive
= 0;
2987 grub_file_close(file
);
2993 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2998 const char *isopath
= NULL
;
3000 ventoy_mbr_head mbr
;
3007 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3010 isopath
= grub_env_get("vtoy_iso_part");
3013 debug("isopath is null %p\n", isopath
);
3017 debug("isopath is %s\n", isopath
);
3019 for (id
= 0; id
< 30 && (find
== 0); id
++)
3021 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3022 if (grub_strstr(isopath
, hdname
))
3024 debug("skip %s ...\n", hdname
);
3028 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3030 disk
= grub_disk_open(hdname
);
3033 debug("%s not exist\n", hdname
);
3037 grub_memset(&mbr
, 0, sizeof(mbr
));
3038 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3040 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3042 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3043 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3046 grub_env_set(args
[0], hdname
);
3050 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3054 debug("read %s failed\n", hdname
);
3057 grub_disk_close(disk
);
3063 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3074 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3077 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3080 debug("failed to open file %s\n", args
[0]);
3084 buf
= grub_malloc(len
);
3091 grub_file_read(file
, buf
, len
- 1);
3093 ventoy_get_line(buf
);
3094 ventoy_set_env(args
[1], buf
);
3098 grub_check_free(buf
);
3099 grub_file_close(file
);
3104 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3109 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3110 "0 %llu linear /dev/ventoy %llu\n",
3111 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3116 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3118 char *device_name
= NULL
;
3119 grub_device_t dev
= NULL
;
3124 g_part_list_pos
= 0;
3125 grub_env_unset("vtoy_img_part_file");
3132 device_name
= grub_file_get_device_name(args
[0]);
3135 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3139 dev
= grub_device_open(device_name
);
3142 debug("grub_device_open failed, %s\n", device_name
);
3146 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3148 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3149 grub_env_set("vtoy_img_part_file", buf
);
3153 check_free(device_name
, grub_free
);
3154 check_free(dev
, grub_device_close
);
3160 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3171 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3174 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3177 debug("failed to open file %s\n", args
[0]);
3181 buf
= grub_malloc(file
->size
+ 1);
3187 buf
[file
->size
] = 0;
3188 grub_file_read(file
, buf
, file
->size
);
3190 if (grub_strstr(buf
, args
[1]))
3197 grub_check_free(buf
);
3198 grub_file_close(file
);
3203 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3208 ventoy_iso9660_vd pvd
;
3215 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3218 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3221 debug("failed to open file %s\n", args
[0]);
3225 grub_file_seek(file
, 16 * 2048);
3226 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3227 if (len
!= sizeof(pvd
))
3229 debug("failed to read pvd %d\n", len
);
3233 grub_memset(buf
, 0, sizeof(buf
));
3234 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3235 ventoy_set_env(args
[1], buf
);
3237 grub_memset(buf
, 0, sizeof(buf
));
3238 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3239 ventoy_set_env(args
[2], buf
);
3242 grub_file_close(file
);
3247 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3258 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3261 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3264 debug("failed to open file %s\n", args
[0]);
3268 grub_memset(buf
, 0, sizeof(buf
));
3269 grub_file_seek(file
, 16 * 2048 + 813);
3270 len
= (int)grub_file_read(file
, buf
, 17);
3273 debug("failed to read create date %d\n", len
);
3277 ventoy_set_env(args
[1], buf
);
3280 grub_file_close(file
);
3285 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3291 ventoy_env_hook_root(1);
3296 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3302 ventoy_env_hook_root(0);
3307 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3314 int image_sector_size
;
3316 ventoy_chain_head
*chain
;
3317 ventoy_img_chunk
*chunk
;
3318 ventoy_os_param
*osparam
;
3319 ventoy_image_location
*location
;
3320 ventoy_image_disk_region
*region
;
3321 struct grub_acpi_table_header
*acpi
;
3330 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3332 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3338 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3340 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3342 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3346 img_chunk_num
= chain
->img_chunk_num
;
3348 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3349 datalen
= sizeof(ventoy_os_param
) + loclen
;
3351 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3352 acpi
= grub_zalloc(buflen
);
3358 /* Step1: Fill acpi table header */
3359 grub_memcpy(acpi
->signature
, "VTOY", 4);
3360 acpi
->length
= buflen
;
3362 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3363 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3365 acpi
->creator_id
[0] = 1;
3366 acpi
->creator_rev
= 1;
3368 /* Step2: Fill data */
3369 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3370 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3371 osparam
->vtoy_img_location_addr
= 0;
3372 osparam
->vtoy_img_location_len
= loclen
;
3373 osparam
->chksum
= 0;
3374 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3376 location
= (ventoy_image_location
*)(osparam
+ 1);
3377 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3378 location
->image_sector_size
= image_sector_size
;
3379 location
->disk_sector_size
= chain
->disk_sector_size
;
3380 location
->region_count
= img_chunk_num
;
3382 region
= location
->regions
;
3383 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3384 if (512 == image_sector_size
)
3386 for (i
= 0; i
< img_chunk_num
; i
++)
3388 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3389 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3390 region
->disk_start_sector
= chunk
->disk_start_sector
;
3397 for (i
= 0; i
< img_chunk_num
; i
++)
3399 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3400 region
->image_start_sector
= chunk
->img_start_sector
;
3401 region
->disk_start_sector
= chunk
->disk_start_sector
;
3407 /* Step3: Fill acpi checksum */
3409 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3411 /* load acpi table */
3412 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3413 grub_script_execute_sourcecode(cmd
);
3417 VENTOY_CMD_RETURN(0);
3420 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3426 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3427 g_ventoy_last_entry
= -1;
3432 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3438 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3443 grub_uint64_t
ventoy_get_part1_size(ventoy_gpt_info
*gpt
)
3445 grub_uint64_t sectors
;
3447 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3449 sectors
= gpt
->PartTbl
[0].LastLBA
+ 1 - gpt
->PartTbl
[0].StartLBA
;
3453 sectors
= gpt
->MBR
.PartTbl
[0].SectorCount
;
3456 return sectors
* 512;
3459 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3461 const char *pos
= filename
+ 1;
3469 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3471 grub_strncpy((char *)data
, filename
, 128);
3482 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3485 char *device_name
= NULL
;
3486 grub_device_t dev
= NULL
;
3487 grub_fs_t fs
= NULL
;
3488 char buf
[128] = {0};
3494 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3498 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3500 device_name
= grub_file_get_device_name(args
[0]);
3503 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3507 dev
= grub_device_open(device_name
);
3510 debug("grub_device_open failed, %s\n", device_name
);
3514 fs
= grub_fs_probe(dev
);
3517 debug("grub_fs_probe failed, %s\n", device_name
);
3521 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3525 ventoy_set_env(args
[2], buf
);
3532 check_free(device_name
, grub_free
);
3533 check_free(dev
, grub_device_close
);
3538 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3548 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3549 if (!g_ventoy_part_info
)
3554 disk
= grub_disk_open(args
[0]);
3557 debug("Failed to open disk %s\n", args
[0]);
3561 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
3563 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3564 grub_disk_close(disk
);
3566 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3567 dev
= grub_device_open(name
);
3570 /* make sure that we are running in a correct Ventoy device */
3571 ret
= ventoy_check_device(dev
);
3572 grub_device_close(dev
);
3583 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3586 grub_uint8_t zeroguid
[16] = {0};
3591 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3594 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3596 if (id
>= 1 && id
<= 128)
3598 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3606 if (id
>= 1 && id
<= 4)
3608 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3618 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3621 char *device_name
= NULL
;
3622 grub_device_t dev
= NULL
;
3623 grub_fs_t fs
= NULL
;
3630 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3634 device_name
= grub_file_get_device_name(args
[0]);
3637 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3641 dev
= grub_device_open(device_name
);
3644 debug("grub_device_open failed, %s\n", device_name
);
3648 fs
= grub_fs_probe(dev
);
3651 debug("grub_fs_probe failed, %s\n", device_name
);
3655 fs
->fs_label(dev
, &label
);
3658 ventoy_set_env(args
[1], label
);
3666 check_free(device_name
, grub_free
);
3667 check_free(dev
, grub_device_close
);
3672 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3676 grub_snprintf((char *)data
, 256, "%s", filename
);
3684 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3687 char *device_name
= NULL
;
3688 grub_device_t dev
= NULL
;
3689 grub_fs_t fs
= NULL
;
3690 char name
[256] ={0};
3696 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3700 device_name
= grub_file_get_device_name(args
[0]);
3703 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3707 dev
= grub_device_open(device_name
);
3710 debug("grub_device_open failed, %s\n", device_name
);
3714 fs
= grub_fs_probe(dev
);
3717 debug("grub_fs_probe failed, %s\n", device_name
);
3721 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3724 ventoy_set_env(args
[2], name
);
3731 check_free(device_name
, grub_free
);
3732 check_free(dev
, grub_device_close
);
3737 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3747 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3751 for (pos
= args
[0]; *pos
; pos
++)
3765 grub_env_set(args
[1], args
[0]);
3775 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3777 struct grub_video_mode_info info
;
3784 if (!g_video_mode_list
)
3786 ventoy_enum_video_mode();
3789 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3791 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3795 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3798 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3800 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3801 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3803 VENTOY_CMD_RETURN(0);
3806 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3808 struct grub_video_mode_info info
;
3815 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3817 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3821 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3824 grub_env_set(args
[0], buf
);
3826 VENTOY_CMD_RETURN(0);
3829 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3837 if (!g_video_mode_list
)
3842 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3843 if (id
< g_video_mode_num
)
3845 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3846 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3849 grub_env_set(args
[1], buf
);
3851 VENTOY_CMD_RETURN(0);
3854 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3856 grub_uint64_t size
= 0;
3859 char fullpath
[256] = {0};
3862 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3865 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3868 debug("grub_file_open failed <%s>\n", fullpath
);
3874 grub_file_close(file
);
3878 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3882 char fullpath
[256] = {0};
3885 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3888 file
= grub_file_open(fullpath
, type
);
3891 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3898 int ventoy_is_file_exist(const char *fmt
, ...)
3903 char buf
[256] = {0};
3905 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
3909 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3912 grub_strncpy(pos
+ len
, "\" ]", 3);
3914 debug("script exec %s\n", buf
);
3916 if (0 == grub_script_execute_sourcecode(buf
))
3924 int ventoy_is_dir_exist(const char *fmt
, ...)
3929 char buf
[256] = {0};
3931 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
3935 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3938 grub_strncpy(pos
+ len
, "\" ]", 3);
3940 debug("script exec %s\n", buf
);
3942 if (0 == grub_script_execute_sourcecode(buf
))
3950 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
3953 grub_uint8_t
*outbuf
;
3954 grub_uint8_t gzHdr
[10] =
3956 0x1F, 0x8B, /* magic */
3959 0,0,0,0, /* mtime */
3964 grub_memset(&s
, 0, sizeof(mz_stream
));
3966 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
3968 outbuf
= (grub_uint8_t
*)mem_out
;
3970 mem_out_len
-= sizeof(gzHdr
) + 8;
3971 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
3972 outbuf
+= sizeof(gzHdr
);
3974 s
.avail_in
= mem_in_len
;
3977 s
.avail_out
= mem_out_len
;
3978 s
.next_out
= outbuf
;
3980 mz_deflate(&s
, MZ_FINISH
);
3984 outbuf
+= s
.total_out
;
3985 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
3986 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
3988 return s
.total_out
+ sizeof(gzHdr
) + 8;
3991 static int ventoy_env_init(void)
3995 grub_env_set("vtdebug_flag", "");
3997 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3998 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3999 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4000 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4002 ventoy_filt_register(0, ventoy_wrapper_open
);
4004 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4007 g_grub_param
->grub_env_get
= grub_env_get
;
4008 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4009 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4010 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4011 grub_env_set("env_param", buf
);
4012 grub_env_set("ventoy_env_param", buf
);
4013 grub_env_export("ventoy_env_param");
4019 static cmd_para ventoy_cmds
[] =
4021 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4022 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4023 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4024 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4025 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4026 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4027 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4028 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4029 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4030 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4031 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4032 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4033 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4034 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4035 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4036 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4037 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4038 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4039 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4040 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4042 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4043 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4044 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4045 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4046 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4047 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4048 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4050 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4051 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4052 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4053 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4054 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4055 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
4056 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
4057 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
4060 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
4061 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
4062 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
4063 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
4064 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
4065 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
4066 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
4067 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
4068 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
4069 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
4070 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
4072 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
4073 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
4074 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
4075 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
4076 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
4077 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
4079 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4080 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
4081 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
4082 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
4083 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
4084 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
4085 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
4086 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
4087 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
4088 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
4090 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4091 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4092 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4093 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4094 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4095 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4096 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
4097 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4099 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4100 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4101 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4104 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4105 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4106 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
4108 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4109 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4110 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4113 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4114 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4115 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4116 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4117 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4118 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4119 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4120 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
4121 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
4122 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4124 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4125 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4126 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4132 GRUB_MOD_INIT(ventoy
)
4135 cmd_para
*cur
= NULL
;
4139 ventoy_arch_mode_init();
4141 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4143 cur
= ventoy_cmds
+ i
;
4144 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4145 cur
->summary
, cur
->description
, cur
->parser
);
4149 GRUB_MOD_FINI(ventoy
)
4153 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4155 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);