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/ventoy.h>
46 #include "ventoy_def.h"
48 GRUB_MOD_LICENSE ("GPLv3+");
50 int g_ventoy_debug
= 0;
51 static int g_efi_os
= 0xFF;
52 initrd_info
*g_initrd_img_list
= NULL
;
53 initrd_info
*g_initrd_img_tail
= NULL
;
54 int g_initrd_img_count
= 0;
55 int g_valid_initrd_count
= 0;
56 int g_default_menu_mode
= 0;
57 int g_filt_dot_underscore_file
= 0;
58 int g_sort_case_sensitive
= 0;
59 int g_tree_view_menu_style
= 0;
60 static grub_file_t g_old_file
;
61 static int g_ventoy_last_entry_back
;
64 char g_img_swap_tmp_buf
[1024];
65 img_info g_img_swap_tmp
;
66 img_info
*g_ventoy_img_list
= NULL
;
68 int g_ventoy_img_count
= 0;
70 grub_device_t g_enum_dev
= NULL
;
71 grub_fs_t g_enum_fs
= NULL
;
72 img_iterator_node g_img_iterator_head
;
73 img_iterator_node
*g_img_iterator_tail
= NULL
;
75 grub_uint8_t g_ventoy_break_level
= 0;
76 grub_uint8_t g_ventoy_debug_level
= 0;
77 grub_uint8_t g_ventoy_chain_type
= 0;
79 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
80 grub_uint32_t g_ventoy_cpio_size
= 0;
81 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
82 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
84 int g_plugin_image_list
= 0;
86 ventoy_grub_param
*g_grub_param
= NULL
;
88 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
90 ventoy_img_chunk_list g_img_chunk_list
;
92 int g_wimboot_enable
= 0;
93 ventoy_img_chunk_list g_wimiso_chunk_list
;
94 char *g_wimiso_path
= NULL
;
96 int g_vhdboot_enable
= 0;
98 grub_uint64_t g_conf_replace_offset
= 0;
99 grub_uint64_t g_svd_replace_offset
= 0;
100 conf_replace
*g_conf_replace_node
= NULL
;
101 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
102 int g_conf_replace_new_len
= 0;
103 int g_conf_replace_new_len_align
= 0;
105 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
107 static char *g_tree_script_buf
= NULL
;
108 static int g_tree_script_pos
= 0;
110 static char *g_list_script_buf
= NULL
;
111 static int g_list_script_pos
= 0;
113 static char *g_part_list_buf
= NULL
;
114 static int g_part_list_pos
= 0;
116 static int g_video_mode_max
= 0;
117 static int g_video_mode_num
= 0;
118 static ventoy_video_mode
*g_video_mode_list
= NULL
;
120 static const char *g_menu_class
[] =
122 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
125 static const char *g_menu_prefix
[] =
127 "iso", "wim", "efi", "img", "vhd", "vtoy"
130 void ventoy_debug(const char *fmt
, ...)
134 va_start (args
, fmt
);
135 grub_vprintf (fmt
, args
);
139 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
149 for (i
= 0; i
< 16; i
++)
151 grub_printf("%02x ", guid
[i
]);
156 int ventoy_is_efi_os(void)
160 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
166 static int ventoy_get_fs_type(const char *fs
)
170 return ventoy_fs_max
;
172 else if (grub_strncmp(fs
, "exfat", 5) == 0)
174 return ventoy_fs_exfat
;
176 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
178 return ventoy_fs_ntfs
;
180 else if (grub_strncmp(fs
, "ext", 3) == 0)
182 return ventoy_fs_ext
;
184 else if (grub_strncmp(fs
, "xfs", 3) == 0)
186 return ventoy_fs_xfs
;
188 else if (grub_strncmp(fs
, "udf", 3) == 0)
190 return ventoy_fs_udf
;
192 else if (grub_strncmp(fs
, "fat", 3) == 0)
194 return ventoy_fs_fat
;
197 return ventoy_fs_max
;
200 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
219 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
221 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
225 static grub_err_t
ventoy_fs_close(grub_file_t file
)
227 grub_file_close(g_old_file
);
228 grub_free(file
->data
);
236 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
242 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
247 for (i
= 0; i
< g_video_mode_num
; i
++)
249 if (g_video_mode_list
[i
].width
== info
->width
&&
250 g_video_mode_list
[i
].height
== info
->height
&&
251 g_video_mode_list
[i
].bpp
== info
->bpp
)
257 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
258 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
259 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
262 if (g_video_mode_num
== g_video_mode_max
)
264 g_video_mode_max
*= 2;
265 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
271 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
273 if (v1
->bpp
== v2
->bpp
)
275 if (v1
->width
== v2
->width
)
277 if (v1
->height
== v2
->height
)
283 return (v1
->height
< v2
->height
) ? -1 : 1;
288 return (v1
->width
< v2
->width
) ? -1 : 1;
293 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
297 static int ventoy_enum_video_mode(void)
300 grub_video_adapter_t adapter
;
301 grub_video_driver_id_t id
;
302 ventoy_video_mode mode
;
304 g_video_mode_num
= 0;
305 g_video_mode_max
= 1024;
306 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
307 if (!g_video_mode_list
)
312 #ifdef GRUB_MACHINE_PCBIOS
313 grub_dl_load ("vbe");
316 id
= grub_video_get_driver_id ();
318 FOR_VIDEO_ADAPTERS (adapter
)
320 if (!adapter
->iterate
||
321 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
322 adapter
->init() != GRUB_ERR_NONE
)))
327 adapter
->iterate(ventoy_video_hook
, NULL
);
329 if (adapter
->id
!= id
)
335 /* sort video mode */
336 for (i
= 0; i
< g_video_mode_num
; i
++)
337 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
339 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
341 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
342 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
343 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
347 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
350 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
354 static struct grub_fs vtoy_fs
=
359 .fs_read
= ventoy_fs_read
,
360 .fs_close
= ventoy_fs_close
,
370 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
376 file
->data
= grub_malloc(rawFile
->size
+ 4096);
382 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
383 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
385 g_old_file
= rawFile
;
387 file
->size
= rawFile
->size
+ len
;
388 file
->device
= rawFile
->device
;
390 file
->not_easily_seekable
= 1;
395 static int ventoy_check_decimal_var(const char *name
, long *value
)
397 const char *value_str
= NULL
;
399 value_str
= grub_env_get(name
);
400 if (NULL
== value_str
)
402 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
405 if (!ventoy_is_decimal(value_str
))
407 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
410 *value
= grub_strtol(value_str
, NULL
, 10);
412 return GRUB_ERR_NONE
;
415 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
419 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
422 if (0 == grub_strcmp(args
[0], "on"))
425 grub_env_set("vtdebug_flag", "debug");
430 grub_env_set("vtdebug_flag", "");
433 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
436 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
440 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
442 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
443 grub_printf(" level:\r\n");
444 grub_printf(" 01/11: busybox / (+cat log)\r\n");
445 grub_printf(" 02/12: initrd / (+cat log)\r\n");
446 grub_printf(" 03/13: hook / (+cat log)\r\n");
448 grub_printf(" debug:\r\n");
449 grub_printf(" 0: debug is off\r\n");
450 grub_printf(" 1: debug is on\r\n");
452 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
455 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
457 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
459 g_ventoy_debug_level
= 1;
462 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
465 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
474 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
477 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
509 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
514 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
516 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
519 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
524 value_long
+= grub_strtol(args
[1], NULL
, 10);
526 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
527 grub_env_set(args
[0], buf
);
529 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
532 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
547 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
550 debug("failed to open file <%s> for udf check\n", args
[0]);
554 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
556 grub_env_set(args
[1], buf
);
558 grub_file_close(file
);
564 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
572 g_wimboot_enable
= 0;
573 grub_check_free(g_wimiso_path
);
574 grub_check_free(g_wimiso_chunk_list
.chunk
);
576 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
582 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
583 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
584 if (NULL
== g_wimiso_chunk_list
.chunk
)
586 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
589 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
590 g_wimiso_chunk_list
.cur_chunk
= 0;
592 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
594 g_wimboot_enable
= 1;
595 g_wimiso_path
= grub_strdup(args
[0]);
597 grub_file_close(file
);
602 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
608 grub_uint32_t offset
;
610 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
613 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
617 len
= (int)file
->size
;
619 data
= (char *)grub_malloc(file
->size
);
625 grub_file_read(file
, data
, file
->size
);
626 grub_file_close(file
);
628 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
629 grub_script_execute_sourcecode(exec
);
631 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
632 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
633 grub_file_close(file
);
635 grub_script_execute_sourcecode("loopback -d efiboot");
639 *direntoff
= offset
+ 2;
644 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
654 ventoy_iso9660_override
*dirent
;
663 totlen
= sizeof(ventoy_chain_head
);
665 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
667 debug("failed to load efiboot template %d\n", len
);
673 debug("efiboot template len:%d offset:%d\n", len
, offset
);
675 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
678 debug("failed to open file <%s>\n", args
[0]);
682 totlen
+= ventoy_align_2k(file
->size
);
684 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
685 dirent
->first_sector
= len
/ 2048;
686 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
687 dirent
->size
= (grub_uint32_t
)file
->size
;
688 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
690 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
692 #ifdef GRUB_MACHINE_EFI
693 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
695 data
= (char *)grub_malloc(totlen
);
698 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
700 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
701 grub_check_free(buf
);
703 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
704 grub_file_close(file
);
706 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
707 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
708 grub_env_set(name
, value
);
710 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
711 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
712 grub_env_set(name
, value
);
717 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
734 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
737 debug("failed to open file <%s>\n", args
[0]);
741 #ifdef GRUB_MACHINE_EFI
742 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
744 buf
= (char *)grub_malloc(file
->size
);
747 grub_file_read(file
, buf
, file
->size
);
749 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
750 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
751 grub_env_set(name
, value
);
753 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
754 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
755 grub_env_set(name
, value
);
757 grub_file_close(file
);
763 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
781 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
784 debug("failed to open file <%s> for udf check\n", args
[0]);
788 headlen
= sizeof(ventoy_chain_head
);
790 #ifdef GRUB_MACHINE_EFI
791 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
793 buf
= (char *)grub_malloc(headlen
+ file
->size
);
796 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
798 grub_file_read(file
, buf
+ headlen
, file
->size
);
800 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
801 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
802 grub_env_set(name
, value
);
804 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
805 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
806 grub_env_set(name
, value
);
808 grub_file_close(file
);
814 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
823 if (args
[0][0] == '1')
825 grub_iso9660_set_nojoliet(1);
829 grub_iso9660_set_nojoliet(0);
835 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
840 grub_uint8_t buf
[32];
851 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
854 debug("failed to open file <%s> for udf check\n", args
[0]);
858 for (i
= 16; i
< 32; i
++)
860 grub_file_seek(file
, i
* 2048);
861 grub_file_read(file
, buf
, sizeof(buf
));
869 grub_file_seek(file
, i
* 2048);
870 grub_file_read(file
, buf
, sizeof(buf
));
872 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
875 grub_file_seek(file
, i
* 2048);
876 grub_file_read(file
, buf
, sizeof(buf
));
878 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
879 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
885 grub_file_close(file
);
887 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
892 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
894 long value_long1
= 0;
895 long value_long2
= 0;
897 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
899 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
902 value_long1
= grub_strtol(args
[0], NULL
, 10);
903 value_long2
= grub_strtol(args
[2], NULL
, 10);
905 if (0 == grub_strcmp(args
[1], "eq"))
907 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
909 else if (0 == grub_strcmp(args
[1], "ne"))
911 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
913 else if (0 == grub_strcmp(args
[1], "gt"))
915 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
917 else if (0 == grub_strcmp(args
[1], "lt"))
919 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
921 else if (0 == grub_strcmp(args
[1], "ge"))
923 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
925 else if (0 == grub_strcmp(args
[1], "le"))
927 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
931 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
937 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
944 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
947 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
948 pos
= grub_strstr(buf
, ",");
954 grub_env_set(args
[1], buf
);
956 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
959 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
965 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
971 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
974 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
976 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
977 if (0 == grub_script_execute_sourcecode(buf
))
979 debug("file %s exist, ventoy_compatible YES\n", buf
);
980 grub_env_set("ventoy_compatible", "YES");
981 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
985 debug("file %s NOT exist\n", buf
);
989 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
990 pos
= grub_strstr(buf
, ")");
996 disk
= grub_disk_open(buf
);
999 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1000 grub_disk_close(disk
);
1002 g_img_swap_tmp_buf
[703] = 0;
1003 for (i
= 318; i
< 703; i
++)
1005 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1006 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1008 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1009 grub_env_set("ventoy_compatible", "YES");
1010 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1016 debug("failed to open disk <%s>\n", buf
);
1019 grub_env_set("ventoy_compatible", "NO");
1020 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1023 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1029 if (g_plugin_image_list
)
1031 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1034 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1039 if (0 == g_sort_case_sensitive
)
1041 if (grub_islower(c1
))
1043 c1
= c1
- 'a' + 'A';
1046 if (grub_islower(c2
))
1048 c2
= c2
- 'a' + 'A';
1061 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1067 if (g_plugin_image_list
)
1069 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1072 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1077 if (0 == g_sort_case_sensitive
)
1079 if (grub_islower(c1
))
1081 c1
= c1
- 'a' + 'A';
1084 if (grub_islower(c2
))
1086 c2
= c2
- 'a' + 'A';
1099 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1101 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1103 grub_memcpy(img1
, img2
, sizeof(img_info
));
1104 img1
->next
= g_img_swap_tmp
.next
;
1105 img1
->prev
= g_img_swap_tmp
.prev
;
1107 g_img_swap_tmp
.next
= img2
->next
;
1108 g_img_swap_tmp
.prev
= img2
->prev
;
1109 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1112 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1116 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1124 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1128 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1138 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1147 img_iterator_node
*tmp
;
1148 img_iterator_node
*new_node
;
1149 img_iterator_node
*node
= (img_iterator_node
*)data
;
1151 len
= grub_strlen(filename
);
1155 if ((len
== 1 && filename
[0] == '.') ||
1156 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1161 if (!ventoy_img_name_valid(filename
, len
))
1166 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1171 if (g_plugin_image_list
)
1173 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1174 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1177 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1182 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1185 new_node
->plugin_list_index
= index
;
1186 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1188 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1191 debug("Directory %s ignored...\n", new_node
->dir
);
1192 grub_free(new_node
);
1196 new_node
->tail
= node
->tail
;
1198 new_node
->parent
= node
;
1199 if (!node
->firstchild
)
1201 node
->firstchild
= new_node
;
1204 if (g_img_iterator_tail
)
1206 g_img_iterator_tail
->next
= new_node
;
1207 g_img_iterator_tail
= new_node
;
1211 g_img_iterator_head
.next
= new_node
;
1212 g_img_iterator_tail
= new_node
;
1218 debug("Find a file %s\n", filename
);
1224 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1226 type
= img_type_iso
;
1228 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1230 type
= img_type_wim
;
1232 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1233 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1235 type
= img_type_vhd
;
1237 #ifdef GRUB_MACHINE_EFI
1238 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1240 type
= img_type_efi
;
1243 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1245 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1247 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1248 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1253 type
= img_type_img
;
1255 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1257 type
= img_type_vtoy
;
1264 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1269 if (g_plugin_image_list
)
1271 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1272 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1275 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1280 img
= grub_zalloc(sizeof(img_info
));
1284 img
->plugin_list_index
= index
;
1285 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1287 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1289 img
->size
= info
->size
;
1292 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1295 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1297 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1302 if (g_ventoy_img_list
)
1304 tail
= *(node
->tail
);
1310 g_ventoy_img_list
= img
;
1313 img
->id
= g_ventoy_img_count
;
1315 if (node
&& NULL
== node
->firstiso
)
1317 node
->firstiso
= img
;
1328 *((img_info
**)(node
->tail
)) = img
;
1329 g_ventoy_img_count
++;
1331 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1332 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1335 img
->class = g_menu_class
[type
];
1337 img
->menu_prefix
= g_menu_prefix
[type
];
1339 if (img_type_iso
== type
)
1341 if (ventoy_plugin_check_memdisk(img
->path
))
1343 img
->menu_prefix
= "miso";
1347 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1354 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1356 int len
= GRUB_UINT_MAX
;
1357 const char *value
= NULL
;
1358 char name
[32] = {0};
1359 char plat
[32] = {0};
1360 char guidstr
[32] = {0};
1361 ventoy_guid guid
= VENTOY_GUID
;
1362 const char *fmt1
= NULL
;
1363 const char *fmt2
= NULL
;
1364 const char *fmt3
= NULL
;
1365 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1366 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1367 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1368 const char fmtcode
[]={
1369 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1370 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1371 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1372 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1373 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1374 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1377 grub_memset(name
, 0, sizeof(name
));
1378 puint
[0] = grub_swap_bytes32(0x56454e54);
1379 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1380 puint
[2] = grub_swap_bytes32(0x45525349);
1381 puint
[1] = grub_swap_bytes32(0x4f595f56);
1382 value
= ventoy_get_env(name
);
1384 grub_memset(name
, 0, sizeof(name
));
1385 puint
[1] = grub_swap_bytes32(0x5f544f50);
1386 puint
[0] = grub_swap_bytes32(0x56544c45);
1387 fmt1
= ventoy_get_env(name
);
1393 grub_memset(name
, 0, sizeof(name
));
1394 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1395 puint
[0] = grub_swap_bytes32(0x56544c45);
1396 fmt2
= ventoy_get_env(name
);
1398 grub_memset(name
, 0, sizeof(name
));
1399 puint
[1] = grub_swap_bytes32(0x5f434c52);
1400 puint
[0] = grub_swap_bytes32(0x56544c45);
1401 fmt3
= ventoy_get_env(name
);
1403 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1405 #if defined (GRUB_MACHINE_EFI)
1406 puint2
[0] = grub_swap_bytes32(0x55454649);
1408 puint2
[0] = grub_swap_bytes32(0x42494f53);
1411 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1412 #pragma GCC diagnostic push
1413 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1414 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1415 fmt1
? fmt1
: fmtdata
,
1416 fmt2
? fmt2
: fmtdata
+ 4,
1417 value
? value
: "", plat
, guidstr
,
1418 fmt3
? fmt3
: fmtdata
+ 6);
1419 #pragma GCC diagnostic pop
1421 grub_memset(name
, 0, sizeof(name
));
1422 puint
[0] = grub_swap_bytes32(0x76746f79);
1423 puint
[2] = grub_swap_bytes32(0x656e7365);
1424 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1425 ventoy_set_env(name
, guidstr
);
1430 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1432 img_info
*minimg
= NULL
;
1433 img_info
*img
= (img_info
*)(node
->firstiso
);
1435 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1437 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1452 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1454 img_iterator_node
*Minchild
= NULL
;
1455 img_iterator_node
*child
= node
->firstchild
;
1457 while (child
&& child
->parent
== node
)
1459 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1463 child
= child
->next
;
1468 Minchild
->select
= 1;
1474 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1477 img_info
*img
= NULL
;
1478 const char *dir_class
= NULL
;
1479 const char *dir_alias
= NULL
;
1480 img_iterator_node
*child
= NULL
;
1482 if (node
->isocnt
== 0 || node
->done
== 1)
1487 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1489 offset
= node
->parent
->dirlen
;
1492 if (node
== &g_img_iterator_head
)
1494 if (g_default_menu_mode
== 0)
1496 if (g_tree_view_menu_style
== 0)
1498 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1499 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1500 " echo 'return ...' \n"
1505 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1506 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1514 node
->dir
[node
->dirlen
- 1] = 0;
1515 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1518 dir_class
= "vtoydir";
1521 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1524 if (g_tree_view_menu_style
== 0)
1526 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1527 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1528 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1532 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1533 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1534 dir_alias
, dir_class
, node
->dir
+ offset
);
1539 dir_alias
= node
->dir
+ offset
;
1541 if (g_tree_view_menu_style
== 0)
1543 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1544 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1545 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1549 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1550 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1551 dir_alias
, dir_class
, node
->dir
+ offset
);
1555 if (g_tree_view_menu_style
== 0)
1557 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1558 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1559 " echo 'return ...' \n"
1564 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1565 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1571 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1573 ventoy_dynamic_tree_menu(child
);
1576 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1578 if (g_tree_view_menu_style
== 0)
1580 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1581 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1584 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1585 img
->unsupport
? "[***********] " : "",
1586 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1588 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1592 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1593 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1596 img
->unsupport
? "[***********] " : "",
1597 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1599 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1603 if (node
!= &g_img_iterator_head
)
1605 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1612 int ventoy_check_device_result(int ret
)
1616 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1617 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1618 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1622 grub_printf(VTOY_WARNING
"\n");
1623 grub_printf(VTOY_WARNING
"\n");
1624 grub_printf(VTOY_WARNING
"\n\n\n");
1626 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1627 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1629 grub_printf("\n\nWill exit after 10 seconds ...... ");
1637 int ventoy_check_device(grub_device_t dev
)
1640 grub_uint64_t offset
;
1645 struct grub_partition
*partition
;
1647 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1649 return ventoy_check_device_result(1 | 0x1000);
1652 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1653 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1654 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
1656 return ventoy_check_device_result(2 | 0x1000);
1659 /* We must have partition 2 */
1660 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1663 return ventoy_check_device_result(3 | 0x1000);
1666 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1668 grub_file_close(file
);
1669 return ventoy_check_device_result(4 | 0x1000);
1672 partition
= dev
->disk
->partition
;
1673 if (partition
->number
!= 0 || partition
->start
!= 2048)
1675 return ventoy_check_device_result(5);
1678 offset
= partition
->start
+ partition
->len
;
1679 partition
= file
->device
->disk
->partition
;
1680 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1682 grub_file_close(file
);
1683 return ventoy_check_device_result(6);
1685 grub_file_close(file
);
1687 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1688 dev2
= grub_device_open(devname
);
1691 return ventoy_check_device_result(7);
1694 fs
= grub_fs_probe(dev2
);
1697 grub_device_close(dev2
);
1698 return ventoy_check_device_result(8);
1701 fs
->fs_label(dev2
, &label
);
1702 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1704 grub_device_close(dev2
);
1705 return ventoy_check_device_result(9);
1708 grub_device_close(dev2
);
1709 return ventoy_check_device_result(0);
1712 static int ventoy_set_default_menu(void)
1718 const char *strdata
= NULL
;
1719 img_info
*cur
= NULL
;
1720 img_info
*default_node
= NULL
;
1721 const char *default_image
= NULL
;
1723 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1724 if (default_image
&& default_image
[0] == '/')
1726 img_len
= grub_strlen(default_image
);
1728 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1730 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1742 if (0 == g_default_menu_mode
)
1744 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1748 def
= grub_strdup(default_image
);
1754 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1756 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1757 if (strdata
&& strdata
[0] == '/')
1759 pos
= def
+ grub_strlen(strdata
);
1770 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1773 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1777 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1785 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1789 grub_device_t dev
= NULL
;
1790 img_info
*cur
= NULL
;
1791 img_info
*tail
= NULL
;
1792 const char *strdata
= NULL
;
1793 char *device_name
= NULL
;
1795 img_iterator_node
*node
= NULL
;
1796 img_iterator_node
*tmp
= NULL
;
1802 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1805 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1807 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1810 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1811 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1813 g_filt_dot_underscore_file
= 1;
1816 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1817 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1819 g_sort_case_sensitive
= 1;
1822 device_name
= grub_file_get_device_name(args
[0]);
1828 g_enum_dev
= dev
= grub_device_open(device_name
);
1834 g_enum_fs
= fs
= grub_fs_probe(dev
);
1840 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1842 debug("unsupported fs:<%s>\n", fs
->name
);
1843 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1847 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1849 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1850 if (strdata
&& strdata
[0] == '1')
1852 g_default_menu_mode
= 1;
1855 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1857 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1859 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1860 if (strdata
&& strdata
[0] == '/')
1862 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1863 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1865 g_img_iterator_head
.dir
[len
++] = '/';
1867 g_img_iterator_head
.dirlen
= len
;
1871 g_img_iterator_head
.dirlen
= 1;
1872 grub_strcpy(g_img_iterator_head
.dir
, "/");
1875 g_img_iterator_head
.tail
= &tail
;
1877 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1879 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1882 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1883 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1885 g_tree_view_menu_style
= 1;
1888 ventoy_set_default_menu();
1890 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1892 ventoy_dynamic_tree_menu(node
);
1896 node
= g_img_iterator_head
.next
;
1904 /* sort image list by image name */
1905 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1907 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1909 if (ventoy_cmp_img(cur
, tail
) > 0)
1911 ventoy_swap_img(cur
, tail
);
1916 if (g_default_menu_mode
== 1)
1918 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1919 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1920 " echo 'return ...' \n"
1924 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1926 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1927 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1930 cur
->unsupport
? "[***********] " : "",
1931 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1933 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1936 g_tree_script_buf
[g_tree_script_pos
] = 0;
1937 g_list_script_buf
[g_list_script_pos
] = 0;
1939 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1940 grub_env_set(args
[1], buf
);
1944 check_free(device_name
, grub_free
);
1945 check_free(dev
, grub_device_close
);
1947 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1951 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1953 img_info
*next
= NULL
;
1954 img_info
*cur
= g_ventoy_img_list
;
1967 g_ventoy_img_list
= NULL
;
1968 g_ventoy_img_count
= 0;
1970 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1973 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1976 img_info
*cur
= g_ventoy_img_list
;
1980 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1982 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1985 img_id
= grub_strtol(args
[0], NULL
, 10);
1986 if (img_id
>= g_ventoy_img_count
)
1988 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1991 debug("Find image %ld name \n", img_id
);
1993 while (cur
&& img_id
> 0)
2001 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2004 debug("image name is %s\n", cur
->name
);
2006 grub_env_set(args
[1], cur
->name
);
2008 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2011 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2016 const char *id
= NULL
;
2017 img_info
*cur
= g_ventoy_img_list
;
2021 if (argc
< 1 || argc
> 2)
2023 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2026 id
= grub_env_get("chosen");
2028 pos
= grub_strstr(id
, "VID_");
2031 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2035 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2040 if (img_id
== cur
->id
)
2049 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2052 grub_env_set(args
[0], cur
->path
);
2056 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2057 grub_env_set(args
[1], value
);
2060 g_svd_replace_offset
= 0;
2062 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2065 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2072 device_name
= grub_file_get_device_name(filename
);
2084 pos2
= grub_strstr(pos
, ",");
2087 pos2
= grub_strstr(pos
, ")");
2095 disk
= grub_disk_open(pos
);
2098 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2099 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2100 grub_disk_close(disk
);
2107 grub_free(device_name
);
2111 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2113 eltorito_descriptor desc
;
2115 grub_memset(&desc
, 0, sizeof(desc
));
2116 grub_file_seek(file
, 17 * 2048);
2117 grub_file_read(file
, &desc
, sizeof(desc
));
2119 if (desc
.type
!= 0 || desc
.version
!= 1)
2124 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2125 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2133 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2137 grub_uint8_t buf
[512];
2139 grub_file_seek(file
, sector
* 2048);
2140 grub_file_read(file
, buf
, sizeof(buf
));
2142 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2144 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2148 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2153 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2155 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2157 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2161 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2163 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2168 debug("%s does not contain efi eltorito\n", file
->name
);
2172 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2175 const char *fs
= NULL
;
2176 const char *cdprompt
= NULL
;
2178 grub_uint8_t chksum
= 0;
2181 disk
= file
->device
->disk
;
2182 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2184 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2185 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2186 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2188 pos
= grub_strstr(file
->name
, "/");
2194 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2196 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2198 param
->vtoy_img_size
= file
->size
;
2200 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2201 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2203 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2205 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2206 param
->vtoy_reserved
[4] = 0;
2207 if (g_ventoy_chain_type
== 1) /* Windows */
2209 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2210 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2212 param
->vtoy_reserved
[4] = 1;
2216 fs
= ventoy_get_env("ventoy_fs_probe");
2217 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2219 param
->vtoy_reserved
[3] = 1;
2222 /* calculate checksum */
2223 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2225 chksum
+= *((grub_uint8_t
*)param
+ i
);
2227 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2232 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2234 grub_uint32_t i
= 0;
2235 grub_uint64_t total
= 0;
2236 ventoy_img_chunk
*chunk
= NULL
;
2238 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2240 chunk
= chunklist
->chunk
+ i
;
2242 if (chunk
->disk_start_sector
<= start
)
2244 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2248 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2251 if (total
!= ((file
->size
+ 511) / 512))
2253 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2260 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2264 grub_uint32_t i
= 0;
2265 grub_uint32_t sector
= 0;
2266 grub_uint32_t count
= 0;
2267 grub_off_t size
= 0;
2268 grub_off_t read
= 0;
2270 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2271 if (fs_type
== ventoy_fs_exfat
)
2273 grub_fat_get_file_chunk(start
, file
, chunklist
);
2275 else if (fs_type
== ventoy_fs_ext
)
2277 grub_ext_get_file_chunk(start
, file
, chunklist
);
2281 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2282 file
->read_hook_data
= chunklist
;
2284 for (size
= file
->size
; size
> 0; size
-= read
)
2286 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2287 grub_file_read(file
, NULL
, read
);
2290 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2292 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2293 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2296 if (ventoy_fs_udf
== fs_type
)
2298 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2300 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2301 chunklist
->chunk
[i
].img_start_sector
= sector
;
2302 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2308 len
= (int)grub_strlen(file
->name
);
2309 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2310 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2311 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2312 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2314 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2316 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2326 chunklist
->chunk
[i
].img_start_sector
= sector
;
2327 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2335 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2339 grub_disk_addr_t start
;
2344 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2347 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2350 g_conf_replace_node
= NULL
;
2351 g_conf_replace_offset
= 0;
2353 if (g_img_chunk_list
.chunk
)
2355 grub_free(g_img_chunk_list
.chunk
);
2358 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2360 grub_file_close(file
);
2361 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2364 /* get image chunk data */
2365 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2366 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2367 if (NULL
== g_img_chunk_list
.chunk
)
2369 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2372 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2373 g_img_chunk_list
.cur_chunk
= 0;
2375 start
= file
->device
->disk
->partition
->start
;
2377 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2379 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2380 grub_file_close(file
);
2384 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2387 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2388 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2391 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2393 grub_uint64_t offset
= 0;
2394 grub_uint32_t align
= 0;
2395 grub_file_t file
= NULL
;
2396 conf_replace
*node
= NULL
;
2402 debug("select conf replace argc:%d\n", argc
);
2409 node
= ventoy_plugin_find_conf_replace(args
[1]);
2412 debug("Conf replace not found for %s\n", args
[1]);
2416 debug("Find conf replace for %s\n", args
[1]);
2418 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2421 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2425 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2426 grub_file_close(file
);
2428 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2431 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2435 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2437 if (align
> vtoy_max_replace_file_size
)
2439 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2443 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2444 g_conf_replace_new_len
= (int)file
->size
;
2445 g_conf_replace_new_len_align
= align
;
2447 g_conf_replace_node
= node
;
2448 g_conf_replace_offset
= offset
+ 2;
2450 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2455 grub_file_close(file
);
2457 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2460 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2465 char configfile
[128];
2466 install_template
*node
= NULL
;
2472 debug("select auto installation argc:%d\n", argc
);
2479 node
= ventoy_plugin_find_install_template(args
[0]);
2482 debug("Auto install template not found for %s\n", args
[0]);
2486 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2488 node
->cursel
= node
->autosel
- 1;
2489 debug("Auto install template auto select %d\n", node
->autosel
);
2493 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2499 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2500 " echo %s\n}\n", "123");
2502 for (i
= 0; i
< node
->templatenum
; i
++)
2504 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2506 node
->templatepath
[i
].path
);
2509 g_ventoy_menu_esc
= 1;
2510 g_ventoy_suppress_esc
= 1;
2512 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2513 grub_script_execute_sourcecode(configfile
);
2515 g_ventoy_menu_esc
= 0;
2516 g_ventoy_suppress_esc
= 0;
2520 node
->cursel
= g_ventoy_last_entry
- 1;
2522 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2525 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2530 char configfile
[128];
2531 persistence_config
*node
;
2537 debug("select persistence argc:%d\n", argc
);
2544 node
= ventoy_plugin_find_persistent(args
[0]);
2547 debug("Persistence image not found for %s\n", args
[0]);
2551 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2553 node
->cursel
= node
->autosel
- 1;
2554 debug("Persistence image auto select %d\n", node
->autosel
);
2558 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2564 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2565 " echo %s\n}\n", "123");
2567 for (i
= 0; i
< node
->backendnum
; i
++)
2569 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2571 node
->backendpath
[i
].path
);
2575 g_ventoy_menu_esc
= 1;
2576 g_ventoy_suppress_esc
= 1;
2578 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2579 grub_script_execute_sourcecode(configfile
);
2581 g_ventoy_menu_esc
= 0;
2582 g_ventoy_suppress_esc
= 0;
2586 node
->cursel
= g_ventoy_last_entry
- 1;
2588 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2591 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2594 ventoy_img_chunk
*cur
;
2600 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2602 cur
= g_img_chunk_list
.chunk
+ i
;
2603 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2604 cur
->img_start_sector
, cur
->img_end_sector
,
2605 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2609 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2612 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2616 ventoy_img_chunk_list chunklist
;
2621 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2624 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2627 /* get image chunk data */
2628 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2629 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2630 if (NULL
== chunklist
.chunk
)
2632 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2635 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2636 chunklist
.cur_chunk
= 0;
2638 ventoy_get_block_list(file
, &chunklist
, 0);
2640 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2642 grub_printf("########## UNSUPPORTED ###############\n");
2645 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2647 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2649 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2650 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2653 grub_printf("\n==================================\n");
2655 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2657 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2658 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2659 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2660 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2661 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2665 grub_free(chunklist
.chunk
);
2666 grub_file_close(file
);
2668 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2671 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2674 ventoy_grub_param_file_replace
*replace
= NULL
;
2682 replace
= &(g_grub_param
->file_replace
);
2683 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2685 replace
->old_name_cnt
= 0;
2686 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2688 replace
->old_name_cnt
++;
2689 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2692 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2695 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2698 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2706 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2707 grub_printf("%s", g_list_script_buf
);
2711 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2712 grub_printf("%s", g_tree_script_buf
);
2718 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2720 img_info
*cur
= g_ventoy_img_list
;
2728 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2729 grub_printf("name:<%s>\n\n", cur
->name
);
2736 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2742 ventoy_plugin_dump_injection();
2747 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2753 ventoy_plugin_dump_auto_install();
2758 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2764 ventoy_plugin_dump_persistence();
2769 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2780 if (args
[0][0] == '0')
2782 return g_ventoy_memdisk_mode
? 0 : 1;
2784 else if (args
[0][0] == '1')
2786 return g_ventoy_iso_raw
? 0 : 1;
2788 else if (args
[0][0] == '2')
2790 return g_ventoy_iso_uefi_drv
? 0 : 1;
2796 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2798 static int configfile_mode
= 0;
2799 char memfile
[128] = {0};
2806 * args[0]: 0:normal 1:configfile
2807 * args[1]: 0:list_buf 1:tree_buf
2812 debug("Invalid argc %d\n", argc
);
2816 if (args
[0][0] == '0')
2818 if (args
[1][0] == '0')
2820 grub_script_execute_sourcecode(g_list_script_buf
);
2824 grub_script_execute_sourcecode(g_tree_script_buf
);
2829 if (configfile_mode
)
2831 debug("Now already in F3 mode %d\n", configfile_mode
);
2835 if (args
[1][0] == '0')
2837 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2838 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2842 g_ventoy_last_entry
= -1;
2843 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2844 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2847 configfile_mode
= 1;
2848 grub_script_execute_sourcecode(memfile
);
2849 configfile_mode
= 0;
2855 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2866 g_ventoy_case_insensitive
= 1;
2867 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2868 g_ventoy_case_insensitive
= 0;
2874 grub_file_close(file
);
2880 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2885 const char *isopath
= NULL
;
2887 ventoy_mbr_head mbr
;
2894 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2897 isopath
= grub_env_get("vtoy_iso_part");
2900 debug("isopath is null %p\n", isopath
);
2904 debug("isopath is %s\n", isopath
);
2906 for (id
= 0; id
< 30 && (find
== 0); id
++)
2908 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2909 if (grub_strstr(isopath
, hdname
))
2911 debug("skip %s ...\n", hdname
);
2915 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2917 disk
= grub_disk_open(hdname
);
2920 debug("%s not exist\n", hdname
);
2924 grub_memset(&mbr
, 0, sizeof(mbr
));
2925 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2927 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2929 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2930 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2933 grub_env_set(args
[0], hdname
);
2937 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
2941 debug("read %s failed\n", hdname
);
2944 grub_disk_close(disk
);
2950 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2961 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
2964 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2967 debug("failed to open file %s\n", args
[0]);
2971 buf
= grub_malloc(len
);
2978 grub_file_read(file
, buf
, len
- 1);
2980 ventoy_get_line(buf
);
2981 ventoy_set_env(args
[1], buf
);
2985 grub_check_free(buf
);
2986 grub_file_close(file
);
2991 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
2996 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
2997 "0 %llu linear /dev/ventoy %llu\n",
2998 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3003 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3005 char *device_name
= NULL
;
3006 grub_device_t dev
= NULL
;
3011 g_part_list_pos
= 0;
3012 grub_env_unset("vtoy_img_part_file");
3019 device_name
= grub_file_get_device_name(args
[0]);
3022 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3026 dev
= grub_device_open(device_name
);
3029 debug("grub_device_open failed, %s\n", device_name
);
3033 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3035 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3036 grub_env_set("vtoy_img_part_file", buf
);
3040 check_free(device_name
, grub_free
);
3041 check_free(dev
, grub_device_close
);
3047 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3058 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3061 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3064 debug("failed to open file %s\n", args
[0]);
3068 buf
= grub_malloc(file
->size
+ 1);
3074 buf
[file
->size
] = 0;
3075 grub_file_read(file
, buf
, file
->size
);
3077 if (grub_strstr(buf
, args
[1]))
3084 grub_check_free(buf
);
3085 grub_file_close(file
);
3090 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3095 ventoy_iso9660_vd pvd
;
3102 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3105 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3108 debug("failed to open file %s\n", args
[0]);
3112 grub_file_seek(file
, 16 * 2048);
3113 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3114 if (len
!= sizeof(pvd
))
3116 debug("failed to read pvd %d\n", len
);
3120 grub_memset(buf
, 0, sizeof(buf
));
3121 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3122 ventoy_set_env(args
[1], buf
);
3124 grub_memset(buf
, 0, sizeof(buf
));
3125 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3126 ventoy_set_env(args
[2], buf
);
3129 grub_file_close(file
);
3134 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3145 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3148 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3151 debug("failed to open file %s\n", args
[0]);
3155 grub_memset(buf
, 0, sizeof(buf
));
3156 grub_file_seek(file
, 16 * 2048 + 813);
3157 len
= (int)grub_file_read(file
, buf
, 17);
3160 debug("failed to read create date %d\n", len
);
3164 ventoy_set_env(args
[1], buf
);
3167 grub_file_close(file
);
3172 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3178 ventoy_env_hook_root(1);
3183 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3189 ventoy_env_hook_root(0);
3194 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3201 int image_sector_size
;
3203 ventoy_chain_head
*chain
;
3204 ventoy_img_chunk
*chunk
;
3205 ventoy_os_param
*osparam
;
3206 ventoy_image_location
*location
;
3207 ventoy_image_disk_region
*region
;
3208 struct grub_acpi_table_header
*acpi
;
3217 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3219 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3225 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3227 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3229 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3233 img_chunk_num
= chain
->img_chunk_num
;
3235 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3236 datalen
= sizeof(ventoy_os_param
) + loclen
;
3238 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3239 acpi
= grub_zalloc(buflen
);
3245 /* Step1: Fill acpi table header */
3246 grub_memcpy(acpi
->signature
, "VTOY", 4);
3247 acpi
->length
= buflen
;
3249 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3250 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3252 acpi
->creator_id
[0] = 1;
3253 acpi
->creator_rev
= 1;
3255 /* Step2: Fill data */
3256 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3257 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3258 osparam
->vtoy_img_location_addr
= 0;
3259 osparam
->vtoy_img_location_len
= loclen
;
3260 osparam
->chksum
= 0;
3261 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3263 location
= (ventoy_image_location
*)(osparam
+ 1);
3264 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3265 location
->image_sector_size
= image_sector_size
;
3266 location
->disk_sector_size
= chain
->disk_sector_size
;
3267 location
->region_count
= img_chunk_num
;
3269 region
= location
->regions
;
3270 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3271 if (512 == image_sector_size
)
3273 for (i
= 0; i
< img_chunk_num
; i
++)
3275 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3276 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3277 region
->disk_start_sector
= chunk
->disk_start_sector
;
3284 for (i
= 0; i
< img_chunk_num
; i
++)
3286 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3287 region
->image_start_sector
= chunk
->img_start_sector
;
3288 region
->disk_start_sector
= chunk
->disk_start_sector
;
3294 /* Step3: Fill acpi checksum */
3296 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3298 /* load acpi table */
3299 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3300 grub_script_execute_sourcecode(cmd
);
3304 VENTOY_CMD_RETURN(0);
3307 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3313 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3314 g_ventoy_last_entry
= -1;
3319 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3325 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3330 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3332 const char *pos
= filename
+ 1;
3340 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3342 grub_strncpy((char *)data
, filename
, 128);
3353 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3356 char *device_name
= NULL
;
3357 grub_device_t dev
= NULL
;
3358 grub_fs_t fs
= NULL
;
3359 char buf
[128] = {0};
3365 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3369 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3371 device_name
= grub_file_get_device_name(args
[0]);
3374 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3378 dev
= grub_device_open(device_name
);
3381 debug("grub_device_open failed, %s\n", device_name
);
3385 fs
= grub_fs_probe(dev
);
3388 debug("grub_fs_probe failed, %s\n", device_name
);
3392 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3396 ventoy_set_env(args
[2], buf
);
3403 check_free(device_name
, grub_free
);
3404 check_free(dev
, grub_device_close
);
3409 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3419 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3420 if (!g_ventoy_part_info
)
3425 disk
= grub_disk_open(args
[0]);
3428 debug("Failed to open disk %s\n", args
[0]);
3432 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3433 grub_disk_close(disk
);
3435 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3436 dev
= grub_device_open(name
);
3439 /* make sure that we are running in a correct Ventoy device */
3440 ret
= ventoy_check_device(dev
);
3441 grub_device_close(dev
);
3452 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3455 grub_uint8_t zeroguid
[16] = {0};
3460 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3463 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3465 if (id
>= 1 && id
<= 128)
3467 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3475 if (id
>= 1 && id
<= 4)
3477 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3487 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3490 char *device_name
= NULL
;
3491 grub_device_t dev
= NULL
;
3492 grub_fs_t fs
= NULL
;
3499 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3503 device_name
= grub_file_get_device_name(args
[0]);
3506 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3510 dev
= grub_device_open(device_name
);
3513 debug("grub_device_open failed, %s\n", device_name
);
3517 fs
= grub_fs_probe(dev
);
3520 debug("grub_fs_probe failed, %s\n", device_name
);
3524 fs
->fs_label(dev
, &label
);
3527 ventoy_set_env(args
[1], label
);
3535 check_free(device_name
, grub_free
);
3536 check_free(dev
, grub_device_close
);
3541 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3545 grub_snprintf((char *)data
, 256, "%s", filename
);
3553 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3556 char *device_name
= NULL
;
3557 grub_device_t dev
= NULL
;
3558 grub_fs_t fs
= NULL
;
3559 char name
[256] ={0};
3565 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3569 device_name
= grub_file_get_device_name(args
[0]);
3572 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3576 dev
= grub_device_open(device_name
);
3579 debug("grub_device_open failed, %s\n", device_name
);
3583 fs
= grub_fs_probe(dev
);
3586 debug("grub_fs_probe failed, %s\n", device_name
);
3590 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3593 ventoy_set_env(args
[2], name
);
3600 check_free(device_name
, grub_free
);
3601 check_free(dev
, grub_device_close
);
3606 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3616 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3620 for (pos
= args
[0]; *pos
; pos
++)
3634 grub_env_set(args
[1], args
[0]);
3644 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3646 struct grub_video_mode_info info
;
3653 if (!g_video_mode_list
)
3655 ventoy_enum_video_mode();
3658 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3660 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3664 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3667 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3669 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3670 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3672 VENTOY_CMD_RETURN(0);
3675 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3677 struct grub_video_mode_info info
;
3684 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3686 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3690 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3693 grub_env_set(args
[0], buf
);
3695 VENTOY_CMD_RETURN(0);
3698 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3706 if (!g_video_mode_list
)
3711 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3712 if (id
< g_video_mode_num
)
3714 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3715 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3718 grub_env_set(args
[1], buf
);
3720 VENTOY_CMD_RETURN(0);
3723 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3725 grub_uint64_t size
= 0;
3728 char fullpath
[256] = {0};
3731 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3734 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3737 debug("grub_file_open failed <%s>\n", fullpath
);
3743 grub_file_close(file
);
3747 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3751 char fullpath
[256] = {0};
3754 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3757 file
= grub_file_open(fullpath
, type
);
3760 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3767 int ventoy_is_file_exist(const char *fmt
, ...)
3772 char buf
[256] = {0};
3774 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
3778 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3781 grub_strncpy(pos
+ len
, " ]", 2);
3783 debug("script exec %s\n", buf
);
3785 if (0 == grub_script_execute_sourcecode(buf
))
3793 int ventoy_is_dir_exist(const char *fmt
, ...)
3798 char buf
[256] = {0};
3800 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
3804 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3807 grub_strncpy(pos
+ len
, " ]", 2);
3809 debug("script exec %s\n", buf
);
3811 if (0 == grub_script_execute_sourcecode(buf
))
3819 static int ventoy_env_init(void)
3823 grub_env_set("vtdebug_flag", "");
3825 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3826 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3827 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3828 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
3830 ventoy_filt_register(0, ventoy_wrapper_open
);
3832 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3835 g_grub_param
->grub_env_get
= grub_env_get
;
3836 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3837 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3838 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3839 grub_env_set("env_param", buf
);
3840 grub_env_set("ventoy_env_param", buf
);
3841 grub_env_export("ventoy_env_param");
3847 static cmd_para ventoy_cmds
[] =
3849 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3850 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3851 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3852 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3853 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3854 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3855 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3856 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3857 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3858 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3859 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3860 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3861 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3862 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3863 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3864 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3865 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3866 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3867 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
3868 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
3870 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
3871 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3872 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3873 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3874 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3875 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3876 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3878 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
3879 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
3880 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3881 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3882 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3883 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
3884 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
3885 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
3888 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3889 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
3890 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
3891 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
3892 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
3893 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
3894 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
3895 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
3896 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
3897 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
3898 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
3900 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
3901 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
3902 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
3903 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
3904 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
3905 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
3907 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3908 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3909 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
3910 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
3911 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
3912 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
3913 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
3914 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
3915 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
3916 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
3918 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
3919 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
3920 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
3921 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
3922 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
3923 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
3924 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
3925 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
3927 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
3928 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
3929 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
3932 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
3933 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
3934 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
3936 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
3937 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
3938 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
3941 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
3942 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
3943 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
3944 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
3945 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
3946 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
3947 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
3948 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
3950 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
3951 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
3952 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
3958 GRUB_MOD_INIT(ventoy
)
3961 cmd_para
*cur
= NULL
;
3965 #ifdef GRUB_MACHINE_EFI
3966 if (grub_strcmp(GRUB_TARGET_CPU
, "i386") == 0)
3968 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "ia32");
3970 else if (grub_strcmp(GRUB_TARGET_CPU
, "arm64") == 0)
3972 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "aa64");
3976 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "uefi");
3979 grub_snprintf(g_arch_mode_suffix
, sizeof(g_arch_mode_suffix
), "%s", "legacy");
3982 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
3984 cur
= ventoy_cmds
+ i
;
3985 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
3986 cur
->summary
, cur
->description
, cur
->parser
);
3990 GRUB_MOD_FINI(ventoy
)
3994 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
3996 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);