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/relocator.h>
45 #include <grub/charset.h>
46 #include <grub/ventoy.h>
47 #include "ventoy_def.h"
49 GRUB_MOD_LICENSE ("GPLv3+");
51 int g_ventoy_debug
= 0;
52 static int g_efi_os
= 0xFF;
53 initrd_info
*g_initrd_img_list
= NULL
;
54 initrd_info
*g_initrd_img_tail
= NULL
;
55 int g_initrd_img_count
= 0;
56 int g_valid_initrd_count
= 0;
57 int g_default_menu_mode
= 0;
58 int g_filt_dot_underscore_file
= 0;
59 int g_sort_case_sensitive
= 0;
60 int g_tree_view_menu_style
= 0;
61 static grub_file_t g_old_file
;
62 static int g_ventoy_last_entry_back
;
65 char g_img_swap_tmp_buf
[1024];
66 img_info g_img_swap_tmp
;
67 img_info
*g_ventoy_img_list
= NULL
;
69 int g_ventoy_img_count
= 0;
71 grub_device_t g_enum_dev
= NULL
;
72 grub_fs_t g_enum_fs
= NULL
;
73 img_iterator_node g_img_iterator_head
;
74 img_iterator_node
*g_img_iterator_tail
= NULL
;
76 grub_uint8_t g_ventoy_break_level
= 0;
77 grub_uint8_t g_ventoy_debug_level
= 0;
78 grub_uint8_t g_ventoy_chain_type
= 0;
80 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
81 grub_uint32_t g_ventoy_cpio_size
= 0;
82 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
83 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
85 int g_plugin_image_list
= 0;
87 ventoy_grub_param
*g_grub_param
= NULL
;
89 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
91 ventoy_img_chunk_list g_img_chunk_list
;
93 int g_wimboot_enable
= 0;
94 ventoy_img_chunk_list g_wimiso_chunk_list
;
95 char *g_wimiso_path
= NULL
;
97 int g_vhdboot_enable
= 0;
99 grub_uint64_t g_conf_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 on\r\n");
450 grub_printf(" 1: debug is off\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] == '_')
1121 for (i
= 0; i
< namelen
; i
++)
1123 if (filename
[i
] == ' ' || filename
[i
] == '\t')
1128 if ((grub_uint8_t
)(filename
[i
]) >= 127)
1137 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1141 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1151 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1160 img_iterator_node
*tmp
;
1161 img_iterator_node
*new_node
;
1162 img_iterator_node
*node
= (img_iterator_node
*)data
;
1164 len
= grub_strlen(filename
);
1168 if ((len
== 1 && filename
[0] == '.') ||
1169 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1174 if (!ventoy_img_name_valid(filename
, len
))
1179 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1184 if (g_plugin_image_list
)
1186 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1187 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1190 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1195 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1198 new_node
->plugin_list_index
= index
;
1199 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1201 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1204 debug("Directory %s ignored...\n", new_node
->dir
);
1205 grub_free(new_node
);
1209 new_node
->tail
= node
->tail
;
1211 new_node
->parent
= node
;
1212 if (!node
->firstchild
)
1214 node
->firstchild
= new_node
;
1217 if (g_img_iterator_tail
)
1219 g_img_iterator_tail
->next
= new_node
;
1220 g_img_iterator_tail
= new_node
;
1224 g_img_iterator_head
.next
= new_node
;
1225 g_img_iterator_tail
= new_node
;
1231 debug("Find a file %s\n", filename
);
1237 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1239 type
= img_type_iso
;
1241 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1243 type
= img_type_wim
;
1245 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1246 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1248 type
= img_type_vhd
;
1250 #ifdef GRUB_MACHINE_EFI
1251 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1253 type
= img_type_efi
;
1256 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1258 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1260 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1261 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1266 type
= img_type_img
;
1268 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1270 type
= img_type_vtoy
;
1277 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1282 if (g_plugin_image_list
)
1284 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1285 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1288 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1293 img
= grub_zalloc(sizeof(img_info
));
1297 img
->plugin_list_index
= index
;
1298 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1300 for (i
= 0; i
< (int)len
; i
++)
1302 if (filename
[i
] == ' ' || filename
[i
] == '\t' || (0 == grub_isprint(filename
[i
])))
1309 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1311 img
->size
= info
->size
;
1314 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1317 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1319 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1324 if (g_ventoy_img_list
)
1326 tail
= *(node
->tail
);
1332 g_ventoy_img_list
= img
;
1335 img
->id
= g_ventoy_img_count
;
1337 if (node
&& NULL
== node
->firstiso
)
1339 node
->firstiso
= img
;
1350 *((img_info
**)(node
->tail
)) = img
;
1351 g_ventoy_img_count
++;
1353 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1354 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1357 img
->class = g_menu_class
[type
];
1359 img
->menu_prefix
= g_menu_prefix
[type
];
1361 if (img_type_iso
== type
)
1363 if (ventoy_plugin_check_memdisk(img
->path
))
1365 img
->menu_prefix
= "miso";
1369 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1376 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1378 int len
= GRUB_UINT_MAX
;
1379 const char *value
= NULL
;
1380 char name
[32] = {0};
1381 char plat
[32] = {0};
1382 char guidstr
[32] = {0};
1383 ventoy_guid guid
= VENTOY_GUID
;
1384 const char *fmt1
= NULL
;
1385 const char *fmt2
= NULL
;
1386 const char *fmt3
= NULL
;
1387 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1388 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1389 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1390 const char fmtcode
[]={
1391 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1392 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1393 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1394 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1395 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1396 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1399 grub_memset(name
, 0, sizeof(name
));
1400 puint
[0] = grub_swap_bytes32(0x56454e54);
1401 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1402 puint
[2] = grub_swap_bytes32(0x45525349);
1403 puint
[1] = grub_swap_bytes32(0x4f595f56);
1404 value
= ventoy_get_env(name
);
1406 grub_memset(name
, 0, sizeof(name
));
1407 puint
[1] = grub_swap_bytes32(0x5f544f50);
1408 puint
[0] = grub_swap_bytes32(0x56544c45);
1409 fmt1
= ventoy_get_env(name
);
1415 grub_memset(name
, 0, sizeof(name
));
1416 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1417 puint
[0] = grub_swap_bytes32(0x56544c45);
1418 fmt2
= ventoy_get_env(name
);
1420 grub_memset(name
, 0, sizeof(name
));
1421 puint
[1] = grub_swap_bytes32(0x5f434c52);
1422 puint
[0] = grub_swap_bytes32(0x56544c45);
1423 fmt3
= ventoy_get_env(name
);
1425 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1427 #if defined (GRUB_MACHINE_EFI)
1428 puint2
[0] = grub_swap_bytes32(0x55454649);
1430 puint2
[0] = grub_swap_bytes32(0x42494f53);
1433 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1434 #pragma GCC diagnostic push
1435 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1436 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1437 fmt1
? fmt1
: fmtdata
,
1438 fmt2
? fmt2
: fmtdata
+ 4,
1439 value
? value
: "", plat
, guidstr
,
1440 fmt3
? fmt3
: fmtdata
+ 6);
1441 #pragma GCC diagnostic pop
1443 grub_memset(name
, 0, sizeof(name
));
1444 puint
[0] = grub_swap_bytes32(0x76746f79);
1445 puint
[2] = grub_swap_bytes32(0x656e7365);
1446 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1447 ventoy_set_env(name
, guidstr
);
1452 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1454 img_info
*minimg
= NULL
;
1455 img_info
*img
= (img_info
*)(node
->firstiso
);
1457 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1459 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1474 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1476 img_iterator_node
*Minchild
= NULL
;
1477 img_iterator_node
*child
= node
->firstchild
;
1479 while (child
&& child
->parent
== node
)
1481 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1485 child
= child
->next
;
1490 Minchild
->select
= 1;
1496 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1499 img_info
*img
= NULL
;
1500 const char *dir_class
= NULL
;
1501 const char *dir_alias
= NULL
;
1502 img_iterator_node
*child
= NULL
;
1504 if (node
->isocnt
== 0 || node
->done
== 1)
1509 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1511 offset
= node
->parent
->dirlen
;
1514 if (node
== &g_img_iterator_head
)
1516 if (g_default_menu_mode
== 0)
1518 if (g_tree_view_menu_style
== 0)
1520 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1521 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1522 " echo 'return ...' \n"
1527 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1528 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1536 node
->dir
[node
->dirlen
- 1] = 0;
1537 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1540 dir_class
= "vtoydir";
1543 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1546 if (g_tree_view_menu_style
== 0)
1548 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1549 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1550 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1554 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1555 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1556 dir_alias
, dir_class
, node
->dir
+ offset
);
1561 dir_alias
= node
->dir
+ offset
;
1563 if (g_tree_view_menu_style
== 0)
1565 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1566 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1567 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1571 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1572 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1573 dir_alias
, dir_class
, node
->dir
+ offset
);
1577 if (g_tree_view_menu_style
== 0)
1579 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1580 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1581 " echo 'return ...' \n"
1586 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1587 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1593 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1595 ventoy_dynamic_tree_menu(child
);
1598 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1600 if (g_tree_view_menu_style
== 0)
1602 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1603 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1606 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1607 img
->unsupport
? "[***********] " : "",
1608 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1610 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1614 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1615 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1618 img
->unsupport
? "[***********] " : "",
1619 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1621 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1625 if (node
!= &g_img_iterator_head
)
1627 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1634 int ventoy_check_device_result(int ret
)
1638 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1639 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1640 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1644 grub_printf(VTOY_WARNING
"\n");
1645 grub_printf(VTOY_WARNING
"\n");
1646 grub_printf(VTOY_WARNING
"\n\n\n");
1648 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1649 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1651 grub_printf("\n\nWill exit after 10 seconds ...... ");
1659 int ventoy_check_device(grub_device_t dev
)
1662 grub_uint64_t offset
;
1667 struct grub_partition
*partition
;
1669 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1671 return ventoy_check_device_result(1 | 0x1000);
1674 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1675 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1676 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_64", dev
->disk
->name
))
1678 return ventoy_check_device_result(2 | 0x1000);
1681 /* We must have partition 2 */
1682 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1685 return ventoy_check_device_result(3 | 0x1000);
1688 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1690 grub_file_close(file
);
1691 return ventoy_check_device_result(4 | 0x1000);
1694 partition
= dev
->disk
->partition
;
1695 if (partition
->number
!= 0 || partition
->start
!= 2048)
1697 return ventoy_check_device_result(5);
1700 offset
= partition
->start
+ partition
->len
;
1701 partition
= file
->device
->disk
->partition
;
1702 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1704 grub_file_close(file
);
1705 return ventoy_check_device_result(6);
1707 grub_file_close(file
);
1709 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1710 dev2
= grub_device_open(devname
);
1713 return ventoy_check_device_result(7);
1716 fs
= grub_fs_probe(dev2
);
1719 grub_device_close(dev2
);
1720 return ventoy_check_device_result(8);
1723 fs
->fs_label(dev2
, &label
);
1724 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1726 grub_device_close(dev2
);
1727 return ventoy_check_device_result(9);
1730 grub_device_close(dev2
);
1731 return ventoy_check_device_result(0);
1734 static int ventoy_set_default_menu(void)
1740 const char *strdata
= NULL
;
1741 img_info
*cur
= NULL
;
1742 img_info
*default_node
= NULL
;
1743 const char *default_image
= NULL
;
1745 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1746 if (default_image
&& default_image
[0] == '/')
1748 img_len
= grub_strlen(default_image
);
1750 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1752 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1764 if (0 == g_default_menu_mode
)
1766 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1770 def
= grub_strdup(default_image
);
1776 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1778 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1779 if (strdata
&& strdata
[0] == '/')
1781 pos
= def
+ grub_strlen(strdata
);
1792 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1795 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1799 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1807 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1811 grub_device_t dev
= NULL
;
1812 img_info
*cur
= NULL
;
1813 img_info
*tail
= NULL
;
1814 const char *strdata
= NULL
;
1815 char *device_name
= NULL
;
1817 img_iterator_node
*node
= NULL
;
1818 img_iterator_node
*tmp
= NULL
;
1824 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1827 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1829 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1832 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1833 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1835 g_filt_dot_underscore_file
= 1;
1838 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1839 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1841 g_sort_case_sensitive
= 1;
1844 device_name
= grub_file_get_device_name(args
[0]);
1850 g_enum_dev
= dev
= grub_device_open(device_name
);
1856 g_enum_fs
= fs
= grub_fs_probe(dev
);
1862 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1864 debug("unsupported fs:<%s>\n", fs
->name
);
1865 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1869 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1871 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1872 if (strdata
&& strdata
[0] == '1')
1874 g_default_menu_mode
= 1;
1877 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1879 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1881 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1882 if (strdata
&& strdata
[0] == '/')
1884 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1885 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1887 g_img_iterator_head
.dir
[len
++] = '/';
1889 g_img_iterator_head
.dirlen
= len
;
1893 g_img_iterator_head
.dirlen
= 1;
1894 grub_strcpy(g_img_iterator_head
.dir
, "/");
1897 g_img_iterator_head
.tail
= &tail
;
1899 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1901 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1904 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1905 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1907 g_tree_view_menu_style
= 1;
1910 ventoy_set_default_menu();
1912 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1914 ventoy_dynamic_tree_menu(node
);
1918 node
= g_img_iterator_head
.next
;
1926 /* sort image list by image name */
1927 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1929 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1931 if (ventoy_cmp_img(cur
, tail
) > 0)
1933 ventoy_swap_img(cur
, tail
);
1938 if (g_default_menu_mode
== 1)
1940 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1941 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1942 " echo 'return ...' \n"
1946 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1948 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1949 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1952 cur
->unsupport
? "[***********] " : "",
1953 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1955 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1958 g_tree_script_buf
[g_tree_script_pos
] = 0;
1959 g_list_script_buf
[g_list_script_pos
] = 0;
1961 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1962 grub_env_set(args
[1], buf
);
1966 check_free(device_name
, grub_free
);
1967 check_free(dev
, grub_device_close
);
1969 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1973 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1975 img_info
*next
= NULL
;
1976 img_info
*cur
= g_ventoy_img_list
;
1989 g_ventoy_img_list
= NULL
;
1990 g_ventoy_img_count
= 0;
1992 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1995 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1998 img_info
*cur
= g_ventoy_img_list
;
2002 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2004 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2007 img_id
= grub_strtol(args
[0], NULL
, 10);
2008 if (img_id
>= g_ventoy_img_count
)
2010 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2013 debug("Find image %ld name \n", img_id
);
2015 while (cur
&& img_id
> 0)
2023 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2026 debug("image name is %s\n", cur
->name
);
2028 grub_env_set(args
[1], cur
->name
);
2030 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2033 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2038 const char *id
= NULL
;
2039 img_info
*cur
= g_ventoy_img_list
;
2043 if (argc
< 1 || argc
> 2)
2045 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2048 id
= grub_env_get("chosen");
2050 pos
= grub_strstr(id
, "VID_");
2053 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2057 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2062 if (img_id
== cur
->id
)
2071 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2074 grub_env_set(args
[0], cur
->path
);
2078 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2079 grub_env_set(args
[1], value
);
2082 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2085 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2092 device_name
= grub_file_get_device_name(filename
);
2104 pos2
= grub_strstr(pos
, ",");
2107 pos2
= grub_strstr(pos
, ")");
2115 disk
= grub_disk_open(pos
);
2118 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2119 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2120 grub_disk_close(disk
);
2127 grub_free(device_name
);
2131 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2133 eltorito_descriptor desc
;
2135 grub_memset(&desc
, 0, sizeof(desc
));
2136 grub_file_seek(file
, 17 * 2048);
2137 grub_file_read(file
, &desc
, sizeof(desc
));
2139 if (desc
.type
!= 0 || desc
.version
!= 1)
2144 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2145 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2153 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2157 grub_uint8_t buf
[512];
2159 grub_file_seek(file
, sector
* 2048);
2160 grub_file_read(file
, buf
, sizeof(buf
));
2162 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2164 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2168 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2173 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2175 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2177 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2181 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2183 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2188 debug("%s does not contain efi eltorito\n", file
->name
);
2192 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2195 const char *fs
= NULL
;
2196 const char *cdprompt
= NULL
;
2198 grub_uint8_t chksum
= 0;
2201 disk
= file
->device
->disk
;
2202 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2204 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2205 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2206 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2208 pos
= grub_strstr(file
->name
, "/");
2214 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2216 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2218 param
->vtoy_img_size
= file
->size
;
2220 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2221 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2223 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2225 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2226 param
->vtoy_reserved
[4] = 0;
2227 if (g_ventoy_chain_type
== 1) /* Windows */
2229 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2230 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2232 param
->vtoy_reserved
[4] = 1;
2236 fs
= ventoy_get_env("ventoy_fs_probe");
2237 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2239 param
->vtoy_reserved
[3] = 1;
2242 /* calculate checksum */
2243 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2245 chksum
+= *((grub_uint8_t
*)param
+ i
);
2247 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2252 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2254 grub_uint32_t i
= 0;
2255 grub_uint64_t total
= 0;
2256 ventoy_img_chunk
*chunk
= NULL
;
2258 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2260 chunk
= chunklist
->chunk
+ i
;
2262 if (chunk
->disk_start_sector
<= start
)
2264 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2268 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2271 if (total
!= ((file
->size
+ 511) / 512))
2273 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2280 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2284 grub_uint32_t i
= 0;
2285 grub_uint32_t sector
= 0;
2286 grub_uint32_t count
= 0;
2287 grub_off_t size
= 0;
2288 grub_off_t read
= 0;
2290 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2291 if (fs_type
== ventoy_fs_exfat
)
2293 grub_fat_get_file_chunk(start
, file
, chunklist
);
2295 else if (fs_type
== ventoy_fs_ext
)
2297 grub_ext_get_file_chunk(start
, file
, chunklist
);
2301 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2302 file
->read_hook_data
= chunklist
;
2304 for (size
= file
->size
; size
> 0; size
-= read
)
2306 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2307 grub_file_read(file
, NULL
, read
);
2310 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2312 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2313 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2316 if (ventoy_fs_udf
== fs_type
)
2318 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2320 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2321 chunklist
->chunk
[i
].img_start_sector
= sector
;
2322 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2328 len
= (int)grub_strlen(file
->name
);
2329 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2330 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2331 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2332 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2334 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2336 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2346 chunklist
->chunk
[i
].img_start_sector
= sector
;
2347 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2355 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2359 grub_disk_addr_t start
;
2364 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2367 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2370 g_conf_replace_node
= NULL
;
2371 g_conf_replace_offset
= 0;
2373 if (g_img_chunk_list
.chunk
)
2375 grub_free(g_img_chunk_list
.chunk
);
2378 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2380 grub_file_close(file
);
2381 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2384 /* get image chunk data */
2385 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2386 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2387 if (NULL
== g_img_chunk_list
.chunk
)
2389 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2392 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2393 g_img_chunk_list
.cur_chunk
= 0;
2395 start
= file
->device
->disk
->partition
->start
;
2397 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2399 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2400 grub_file_close(file
);
2404 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2407 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2408 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2411 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2413 grub_uint64_t offset
= 0;
2414 grub_uint32_t align
= 0;
2415 grub_file_t file
= NULL
;
2416 conf_replace
*node
= NULL
;
2422 debug("select conf replace argc:%d\n", argc
);
2429 node
= ventoy_plugin_find_conf_replace(args
[1]);
2432 debug("Conf replace not found for %s\n", args
[1]);
2436 debug("Find conf replace for %s\n", args
[1]);
2438 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2441 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2445 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2446 grub_file_close(file
);
2448 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2451 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2455 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2457 if (align
> vtoy_max_replace_file_size
)
2459 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2463 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2464 g_conf_replace_new_len
= (int)file
->size
;
2465 g_conf_replace_new_len_align
= align
;
2467 g_conf_replace_node
= node
;
2468 g_conf_replace_offset
= offset
+ 2;
2470 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2475 grub_file_close(file
);
2477 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2480 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2485 char configfile
[128];
2486 install_template
*node
= NULL
;
2492 debug("select auto installation argc:%d\n", argc
);
2499 node
= ventoy_plugin_find_install_template(args
[0]);
2502 debug("Auto install template not found for %s\n", args
[0]);
2506 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2508 node
->cursel
= node
->autosel
- 1;
2509 debug("Auto install template auto select %d\n", node
->autosel
);
2513 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2519 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2520 " echo %s\n}\n", "123");
2522 for (i
= 0; i
< node
->templatenum
; i
++)
2524 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2526 node
->templatepath
[i
].path
);
2529 g_ventoy_menu_esc
= 1;
2530 g_ventoy_suppress_esc
= 1;
2532 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2533 grub_script_execute_sourcecode(configfile
);
2535 g_ventoy_menu_esc
= 0;
2536 g_ventoy_suppress_esc
= 0;
2540 node
->cursel
= g_ventoy_last_entry
- 1;
2542 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2545 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2550 char configfile
[128];
2551 persistence_config
*node
;
2557 debug("select persistence argc:%d\n", argc
);
2564 node
= ventoy_plugin_find_persistent(args
[0]);
2567 debug("Persistence image not found for %s\n", args
[0]);
2571 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2573 node
->cursel
= node
->autosel
- 1;
2574 debug("Persistence image auto select %d\n", node
->autosel
);
2578 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2584 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2585 " echo %s\n}\n", "123");
2587 for (i
= 0; i
< node
->backendnum
; i
++)
2589 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2591 node
->backendpath
[i
].path
);
2595 g_ventoy_menu_esc
= 1;
2596 g_ventoy_suppress_esc
= 1;
2598 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2599 grub_script_execute_sourcecode(configfile
);
2601 g_ventoy_menu_esc
= 0;
2602 g_ventoy_suppress_esc
= 0;
2606 node
->cursel
= g_ventoy_last_entry
- 1;
2608 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2611 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2614 ventoy_img_chunk
*cur
;
2620 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2622 cur
= g_img_chunk_list
.chunk
+ i
;
2623 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2624 cur
->img_start_sector
, cur
->img_end_sector
,
2625 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2629 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2632 #ifdef GRUB_MACHINE_EFI
2633 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2641 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2644 ulong chain_len
= 0;
2645 char *chain_data
= NULL
;
2646 char *relocator_addr
= NULL
;
2647 grub_relocator_chunk_t ch
;
2648 struct grub_relocator
*relocator
= NULL
;
2649 char envbuf
[64] = { 0 };
2660 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
2661 chain_len
= grub_strtoul(args
[1], NULL
, 10);
2663 relocator
= grub_relocator_new ();
2666 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
2670 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
2671 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
2675 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
2676 grub_relocator_unload (relocator
);
2680 relocator_addr
= get_virtual_current_address(ch
);
2682 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
2684 grub_relocator_unload (relocator
);
2686 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
2687 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
2689 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2693 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2697 ventoy_img_chunk_list chunklist
;
2702 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2705 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2708 /* get image chunk data */
2709 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2710 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2711 if (NULL
== chunklist
.chunk
)
2713 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2716 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2717 chunklist
.cur_chunk
= 0;
2719 ventoy_get_block_list(file
, &chunklist
, 0);
2721 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2723 grub_printf("########## UNSUPPORTED ###############\n");
2726 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2728 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2730 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2731 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2734 grub_printf("\n==================================\n");
2736 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2738 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2739 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2740 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2741 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2742 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2746 grub_free(chunklist
.chunk
);
2747 grub_file_close(file
);
2749 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2752 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2755 ventoy_grub_param_file_replace
*replace
= NULL
;
2763 replace
= &(g_grub_param
->file_replace
);
2764 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2766 replace
->old_name_cnt
= 0;
2767 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2769 replace
->old_name_cnt
++;
2770 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2773 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2776 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2779 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2787 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2788 grub_printf("%s", g_list_script_buf
);
2792 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2793 grub_printf("%s", g_tree_script_buf
);
2799 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2801 img_info
*cur
= g_ventoy_img_list
;
2809 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2810 grub_printf("name:<%s>\n\n", cur
->name
);
2817 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2823 ventoy_plugin_dump_injection();
2828 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2834 ventoy_plugin_dump_auto_install();
2839 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2845 ventoy_plugin_dump_persistence();
2850 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2861 if (args
[0][0] == '0')
2863 return g_ventoy_memdisk_mode
? 0 : 1;
2865 else if (args
[0][0] == '1')
2867 return g_ventoy_iso_raw
? 0 : 1;
2869 else if (args
[0][0] == '2')
2871 return g_ventoy_iso_uefi_drv
? 0 : 1;
2877 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2879 static int configfile_mode
= 0;
2880 char memfile
[128] = {0};
2887 * args[0]: 0:normal 1:configfile
2888 * args[1]: 0:list_buf 1:tree_buf
2893 debug("Invalid argc %d\n", argc
);
2897 if (args
[0][0] == '0')
2899 if (args
[1][0] == '0')
2901 grub_script_execute_sourcecode(g_list_script_buf
);
2905 grub_script_execute_sourcecode(g_tree_script_buf
);
2910 if (configfile_mode
)
2912 debug("Now already in F3 mode %d\n", configfile_mode
);
2916 if (args
[1][0] == '0')
2918 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2919 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2923 g_ventoy_last_entry
= -1;
2924 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2925 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2928 configfile_mode
= 1;
2929 grub_script_execute_sourcecode(memfile
);
2930 configfile_mode
= 0;
2936 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2947 g_ventoy_case_insensitive
= 1;
2948 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2949 g_ventoy_case_insensitive
= 0;
2955 grub_file_close(file
);
2961 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2966 const char *isopath
= NULL
;
2968 ventoy_mbr_head mbr
;
2975 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2978 isopath
= grub_env_get("vtoy_iso_part");
2981 debug("isopath is null %p\n", isopath
);
2985 debug("isopath is %s\n", isopath
);
2987 for (id
= 0; id
< 30 && (find
== 0); id
++)
2989 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2990 if (grub_strstr(isopath
, hdname
))
2992 debug("skip %s ...\n", hdname
);
2996 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2998 disk
= grub_disk_open(hdname
);
3001 debug("%s not exist\n", hdname
);
3005 grub_memset(&mbr
, 0, sizeof(mbr
));
3006 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3008 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3010 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3011 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3014 grub_env_set(args
[0], hdname
);
3018 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3022 debug("read %s failed\n", hdname
);
3025 grub_disk_close(disk
);
3031 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3042 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3045 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3048 debug("failed to open file %s\n", args
[0]);
3052 buf
= grub_malloc(len
);
3059 grub_file_read(file
, buf
, len
- 1);
3061 ventoy_get_line(buf
);
3062 ventoy_set_env(args
[1], buf
);
3066 grub_check_free(buf
);
3067 grub_file_close(file
);
3072 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3077 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3078 "0 %llu linear /dev/ventoy %llu\n",
3079 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3084 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3086 char *device_name
= NULL
;
3087 grub_device_t dev
= NULL
;
3092 g_part_list_pos
= 0;
3093 grub_env_unset("vtoy_img_part_file");
3100 device_name
= grub_file_get_device_name(args
[0]);
3103 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3107 dev
= grub_device_open(device_name
);
3110 debug("grub_device_open failed, %s\n", device_name
);
3114 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3116 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3117 grub_env_set("vtoy_img_part_file", buf
);
3121 check_free(device_name
, grub_free
);
3122 check_free(dev
, grub_device_close
);
3128 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3139 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3142 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3145 debug("failed to open file %s\n", args
[0]);
3149 buf
= grub_malloc(file
->size
+ 1);
3155 buf
[file
->size
] = 0;
3156 grub_file_read(file
, buf
, file
->size
);
3158 if (grub_strstr(buf
, args
[1]))
3165 grub_check_free(buf
);
3166 grub_file_close(file
);
3171 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3176 ventoy_iso9660_vd pvd
;
3183 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3186 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3189 debug("failed to open file %s\n", args
[0]);
3193 grub_file_seek(file
, 16 * 2048);
3194 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3195 if (len
!= sizeof(pvd
))
3197 debug("failed to read pvd %d\n", len
);
3201 grub_memset(buf
, 0, sizeof(buf
));
3202 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3203 ventoy_set_env(args
[1], buf
);
3205 grub_memset(buf
, 0, sizeof(buf
));
3206 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3207 ventoy_set_env(args
[2], buf
);
3210 grub_file_close(file
);
3215 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3226 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3229 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3232 debug("failed to open file %s\n", args
[0]);
3236 grub_memset(buf
, 0, sizeof(buf
));
3237 grub_file_seek(file
, 16 * 2048 + 813);
3238 len
= (int)grub_file_read(file
, buf
, 17);
3241 debug("failed to read create date %d\n", len
);
3245 ventoy_set_env(args
[1], buf
);
3248 grub_file_close(file
);
3253 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3259 ventoy_env_hook_root(1);
3264 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3270 ventoy_env_hook_root(0);
3275 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3282 int image_sector_size
;
3284 ventoy_chain_head
*chain
;
3285 ventoy_img_chunk
*chunk
;
3286 ventoy_os_param
*osparam
;
3287 ventoy_image_location
*location
;
3288 ventoy_image_disk_region
*region
;
3289 struct grub_acpi_table_header
*acpi
;
3298 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3300 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3306 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3308 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3310 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3314 img_chunk_num
= chain
->img_chunk_num
;
3316 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3317 datalen
= sizeof(ventoy_os_param
) + loclen
;
3319 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3320 acpi
= grub_zalloc(buflen
);
3326 /* Step1: Fill acpi table header */
3327 grub_memcpy(acpi
->signature
, "VTOY", 4);
3328 acpi
->length
= buflen
;
3330 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3331 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3333 acpi
->creator_id
[0] = 1;
3334 acpi
->creator_rev
= 1;
3336 /* Step2: Fill data */
3337 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3338 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3339 osparam
->vtoy_img_location_addr
= 0;
3340 osparam
->vtoy_img_location_len
= loclen
;
3341 osparam
->chksum
= 0;
3342 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3344 location
= (ventoy_image_location
*)(osparam
+ 1);
3345 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3346 location
->image_sector_size
= image_sector_size
;
3347 location
->disk_sector_size
= chain
->disk_sector_size
;
3348 location
->region_count
= img_chunk_num
;
3350 region
= location
->regions
;
3351 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3352 if (512 == image_sector_size
)
3354 for (i
= 0; i
< img_chunk_num
; i
++)
3356 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3357 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3358 region
->disk_start_sector
= chunk
->disk_start_sector
;
3365 for (i
= 0; i
< img_chunk_num
; i
++)
3367 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3368 region
->image_start_sector
= chunk
->img_start_sector
;
3369 region
->disk_start_sector
= chunk
->disk_start_sector
;
3375 /* Step3: Fill acpi checksum */
3377 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3379 /* load acpi table */
3380 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3381 grub_script_execute_sourcecode(cmd
);
3385 VENTOY_CMD_RETURN(0);
3388 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3394 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3395 g_ventoy_last_entry
= -1;
3400 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3406 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3411 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3413 const char *pos
= filename
+ 1;
3421 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3423 grub_strncpy((char *)data
, filename
, 128);
3434 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3437 char *device_name
= NULL
;
3438 grub_device_t dev
= NULL
;
3439 grub_fs_t fs
= NULL
;
3440 char buf
[128] = {0};
3446 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3450 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3452 device_name
= grub_file_get_device_name(args
[0]);
3455 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3459 dev
= grub_device_open(device_name
);
3462 debug("grub_device_open failed, %s\n", device_name
);
3466 fs
= grub_fs_probe(dev
);
3469 debug("grub_fs_probe failed, %s\n", device_name
);
3473 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3477 ventoy_set_env(args
[2], buf
);
3484 check_free(device_name
, grub_free
);
3485 check_free(dev
, grub_device_close
);
3490 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3500 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3501 if (!g_ventoy_part_info
)
3506 disk
= grub_disk_open(args
[0]);
3509 debug("Failed to open disk %s\n", args
[0]);
3513 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3514 grub_disk_close(disk
);
3516 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3517 dev
= grub_device_open(name
);
3520 /* make sure that we are running in a correct Ventoy device */
3521 ret
= ventoy_check_device(dev
);
3522 grub_device_close(dev
);
3533 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3536 grub_uint8_t zeroguid
[16] = {0};
3541 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3544 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3546 if (id
>= 1 && id
<= 128)
3548 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3556 if (id
>= 1 && id
<= 4)
3558 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3568 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3571 char *device_name
= NULL
;
3572 grub_device_t dev
= NULL
;
3573 grub_fs_t fs
= NULL
;
3580 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3584 device_name
= grub_file_get_device_name(args
[0]);
3587 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3591 dev
= grub_device_open(device_name
);
3594 debug("grub_device_open failed, %s\n", device_name
);
3598 fs
= grub_fs_probe(dev
);
3601 debug("grub_fs_probe failed, %s\n", device_name
);
3605 fs
->fs_label(dev
, &label
);
3608 ventoy_set_env(args
[1], label
);
3616 check_free(device_name
, grub_free
);
3617 check_free(dev
, grub_device_close
);
3622 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3626 grub_snprintf((char *)data
, 256, "%s", filename
);
3634 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3637 char *device_name
= NULL
;
3638 grub_device_t dev
= NULL
;
3639 grub_fs_t fs
= NULL
;
3640 char name
[256] ={0};
3646 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3650 device_name
= grub_file_get_device_name(args
[0]);
3653 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3657 dev
= grub_device_open(device_name
);
3660 debug("grub_device_open failed, %s\n", device_name
);
3664 fs
= grub_fs_probe(dev
);
3667 debug("grub_fs_probe failed, %s\n", device_name
);
3671 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3674 ventoy_set_env(args
[2], name
);
3681 check_free(device_name
, grub_free
);
3682 check_free(dev
, grub_device_close
);
3687 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3697 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3701 for (pos
= args
[0]; *pos
; pos
++)
3715 grub_env_set(args
[1], args
[0]);
3725 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3727 struct grub_video_mode_info info
;
3734 if (!g_video_mode_list
)
3736 ventoy_enum_video_mode();
3739 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3741 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3745 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3748 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3750 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3751 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3753 VENTOY_CMD_RETURN(0);
3756 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3758 struct grub_video_mode_info info
;
3765 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3767 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3771 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3774 grub_env_set(args
[0], buf
);
3776 VENTOY_CMD_RETURN(0);
3779 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3787 if (!g_video_mode_list
)
3792 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3793 if (id
< g_video_mode_num
)
3795 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3796 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3799 grub_env_set(args
[1], buf
);
3801 VENTOY_CMD_RETURN(0);
3804 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3806 grub_uint64_t size
= 0;
3809 char fullpath
[256] = {0};
3812 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3815 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3818 debug("grub_file_open failed <%s>\n", fullpath
);
3824 grub_file_close(file
);
3828 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3832 char fullpath
[256] = {0};
3835 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3838 file
= grub_file_open(fullpath
, type
);
3841 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3848 int ventoy_is_file_exist(const char *fmt
, ...)
3853 char buf
[256] = {0};
3855 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
3859 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3862 grub_strncpy(pos
+ len
, " ]", 2);
3864 debug("script exec %s\n", buf
);
3866 if (0 == grub_script_execute_sourcecode(buf
))
3874 int ventoy_is_dir_exist(const char *fmt
, ...)
3879 char buf
[256] = {0};
3881 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
3885 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3888 grub_strncpy(pos
+ len
, " ]", 2);
3890 debug("script exec %s\n", buf
);
3892 if (0 == grub_script_execute_sourcecode(buf
))
3900 static int ventoy_env_init(void)
3904 grub_env_set("vtdebug_flag", "");
3906 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3907 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3908 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3909 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
3911 ventoy_filt_register(0, ventoy_wrapper_open
);
3913 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3916 g_grub_param
->grub_env_get
= grub_env_get
;
3917 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3918 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3919 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3920 grub_env_set("env_param", buf
);
3921 grub_env_set("ventoy_env_param", buf
);
3922 grub_env_export("ventoy_env_param");
3928 static cmd_para ventoy_cmds
[] =
3930 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3931 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3932 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3933 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3934 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3935 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3936 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3937 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3938 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3939 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3940 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3941 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3942 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3943 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3944 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3945 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3946 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3947 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3948 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
3949 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
3951 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3952 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3953 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3954 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3955 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3956 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3958 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
3959 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
3960 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3961 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3962 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3963 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
3964 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
3965 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
3968 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3969 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
3970 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
3971 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
3972 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
3973 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
3974 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
3975 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
3976 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
3977 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
3978 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
3980 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
3981 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
3982 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
3983 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
3984 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
3985 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
3987 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3988 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3989 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
3990 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
3991 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
3992 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
3993 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
3994 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
3995 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
3996 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
3998 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
3999 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4000 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4001 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4002 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4003 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4004 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4006 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4007 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
4008 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4009 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4012 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4013 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4015 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4016 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4017 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4020 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4021 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4022 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4023 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4024 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4025 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4026 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4027 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4029 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4030 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4031 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4037 GRUB_MOD_INIT(ventoy
)
4040 cmd_para
*cur
= NULL
;
4044 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4046 cur
= ventoy_cmds
+ i
;
4047 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4048 cur
->summary
, cur
->description
, cur
->parser
);
4052 GRUB_MOD_FINI(ventoy
)
4056 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4058 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);