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("Unsatisfied conditions detected for Ventoy.\n\n");
1649 grub_printf("This is NOT a standard Ventoy device and is NOT officially supported.\n\n");
1650 grub_printf("Recommend to follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1652 grub_printf("\n\nWill exit after 10 seconds ...... ");
1660 int ventoy_check_device(grub_device_t dev
)
1663 grub_uint64_t offset
;
1668 struct grub_partition
*partition
;
1670 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1672 return ventoy_check_device_result(1 | 0x1000);
1675 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1676 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1677 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_64", dev
->disk
->name
))
1679 return ventoy_check_device_result(2 | 0x1000);
1682 /* We must have partition 2 */
1683 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1686 return ventoy_check_device_result(3 | 0x1000);
1689 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1691 grub_file_close(file
);
1692 return ventoy_check_device_result(4 | 0x1000);
1695 partition
= dev
->disk
->partition
;
1696 if (partition
->number
!= 0 || partition
->start
!= 2048)
1698 return ventoy_check_device_result(5);
1701 offset
= partition
->start
+ partition
->len
;
1702 partition
= file
->device
->disk
->partition
;
1703 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1705 grub_file_close(file
);
1706 return ventoy_check_device_result(6);
1708 grub_file_close(file
);
1710 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1711 dev2
= grub_device_open(devname
);
1714 return ventoy_check_device_result(7);
1717 fs
= grub_fs_probe(dev2
);
1720 grub_device_close(dev2
);
1721 return ventoy_check_device_result(8);
1724 fs
->fs_label(dev2
, &label
);
1725 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1727 grub_device_close(dev2
);
1728 return ventoy_check_device_result(9);
1731 grub_device_close(dev2
);
1732 return ventoy_check_device_result(0);
1735 static int ventoy_set_default_menu(void)
1741 const char *strdata
= NULL
;
1742 img_info
*cur
= NULL
;
1743 img_info
*default_node
= NULL
;
1744 const char *default_image
= NULL
;
1746 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1747 if (default_image
&& default_image
[0] == '/')
1749 img_len
= grub_strlen(default_image
);
1751 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1753 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1765 if (0 == g_default_menu_mode
)
1767 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1771 def
= grub_strdup(default_image
);
1777 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1779 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1780 if (strdata
&& strdata
[0] == '/')
1782 pos
= def
+ grub_strlen(strdata
);
1793 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1796 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1800 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1808 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1812 grub_device_t dev
= NULL
;
1813 img_info
*cur
= NULL
;
1814 img_info
*tail
= NULL
;
1815 const char *strdata
= NULL
;
1816 char *device_name
= NULL
;
1818 img_iterator_node
*node
= NULL
;
1819 img_iterator_node
*tmp
= NULL
;
1825 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1828 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1830 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1833 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1834 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1836 g_filt_dot_underscore_file
= 1;
1839 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1840 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1842 g_sort_case_sensitive
= 1;
1845 device_name
= grub_file_get_device_name(args
[0]);
1851 g_enum_dev
= dev
= grub_device_open(device_name
);
1857 g_enum_fs
= fs
= grub_fs_probe(dev
);
1863 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1865 debug("unsupported fs:<%s>\n", fs
->name
);
1866 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1870 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1872 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1873 if (strdata
&& strdata
[0] == '1')
1875 g_default_menu_mode
= 1;
1878 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1880 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1882 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1883 if (strdata
&& strdata
[0] == '/')
1885 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1886 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1888 g_img_iterator_head
.dir
[len
++] = '/';
1890 g_img_iterator_head
.dirlen
= len
;
1894 g_img_iterator_head
.dirlen
= 1;
1895 grub_strcpy(g_img_iterator_head
.dir
, "/");
1898 g_img_iterator_head
.tail
= &tail
;
1900 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1902 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1905 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1906 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1908 g_tree_view_menu_style
= 1;
1911 ventoy_set_default_menu();
1913 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1915 ventoy_dynamic_tree_menu(node
);
1919 node
= g_img_iterator_head
.next
;
1927 /* sort image list by image name */
1928 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1930 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1932 if (ventoy_cmp_img(cur
, tail
) > 0)
1934 ventoy_swap_img(cur
, tail
);
1939 if (g_default_menu_mode
== 1)
1941 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1942 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1943 " echo 'return ...' \n"
1947 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1949 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1950 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1953 cur
->unsupport
? "[***********] " : "",
1954 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1956 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1959 g_tree_script_buf
[g_tree_script_pos
] = 0;
1960 g_list_script_buf
[g_list_script_pos
] = 0;
1962 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1963 grub_env_set(args
[1], buf
);
1967 check_free(device_name
, grub_free
);
1968 check_free(dev
, grub_device_close
);
1970 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1974 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1976 img_info
*next
= NULL
;
1977 img_info
*cur
= g_ventoy_img_list
;
1990 g_ventoy_img_list
= NULL
;
1991 g_ventoy_img_count
= 0;
1993 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1996 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1999 img_info
*cur
= g_ventoy_img_list
;
2003 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2005 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2008 img_id
= grub_strtol(args
[0], NULL
, 10);
2009 if (img_id
>= g_ventoy_img_count
)
2011 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2014 debug("Find image %ld name \n", img_id
);
2016 while (cur
&& img_id
> 0)
2024 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2027 debug("image name is %s\n", cur
->name
);
2029 grub_env_set(args
[1], cur
->name
);
2031 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2034 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2039 const char *id
= NULL
;
2040 img_info
*cur
= g_ventoy_img_list
;
2044 if (argc
< 1 || argc
> 2)
2046 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2049 id
= grub_env_get("chosen");
2051 pos
= grub_strstr(id
, "VID_");
2054 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2058 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2063 if (img_id
== cur
->id
)
2072 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2075 grub_env_set(args
[0], cur
->path
);
2079 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2080 grub_env_set(args
[1], value
);
2083 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2086 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2093 device_name
= grub_file_get_device_name(filename
);
2105 pos2
= grub_strstr(pos
, ",");
2108 pos2
= grub_strstr(pos
, ")");
2116 disk
= grub_disk_open(pos
);
2119 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2120 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2121 grub_disk_close(disk
);
2128 grub_free(device_name
);
2132 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2134 eltorito_descriptor desc
;
2136 grub_memset(&desc
, 0, sizeof(desc
));
2137 grub_file_seek(file
, 17 * 2048);
2138 grub_file_read(file
, &desc
, sizeof(desc
));
2140 if (desc
.type
!= 0 || desc
.version
!= 1)
2145 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2146 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2154 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2158 grub_uint8_t buf
[512];
2160 grub_file_seek(file
, sector
* 2048);
2161 grub_file_read(file
, buf
, sizeof(buf
));
2163 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2165 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2169 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2174 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2176 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2178 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2182 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2184 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2189 debug("%s does not contain efi eltorito\n", file
->name
);
2193 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2196 const char *fs
= NULL
;
2197 const char *cdprompt
= NULL
;
2199 grub_uint8_t chksum
= 0;
2202 disk
= file
->device
->disk
;
2203 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2205 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2206 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2207 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2209 pos
= grub_strstr(file
->name
, "/");
2215 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2217 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2219 param
->vtoy_img_size
= file
->size
;
2221 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2222 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2224 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2226 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2227 param
->vtoy_reserved
[4] = 0;
2228 if (g_ventoy_chain_type
== 1) /* Windows */
2230 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2231 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2233 param
->vtoy_reserved
[4] = 1;
2237 fs
= ventoy_get_env("ventoy_fs_probe");
2238 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2240 param
->vtoy_reserved
[3] = 1;
2243 /* calculate checksum */
2244 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2246 chksum
+= *((grub_uint8_t
*)param
+ i
);
2248 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2253 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2255 grub_uint32_t i
= 0;
2256 grub_uint64_t total
= 0;
2257 ventoy_img_chunk
*chunk
= NULL
;
2259 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2261 chunk
= chunklist
->chunk
+ i
;
2263 if (chunk
->disk_start_sector
<= start
)
2265 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2269 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2272 if (total
!= ((file
->size
+ 511) / 512))
2274 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2281 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2285 grub_uint32_t i
= 0;
2286 grub_uint32_t sector
= 0;
2287 grub_uint32_t count
= 0;
2288 grub_off_t size
= 0;
2289 grub_off_t read
= 0;
2291 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2292 if (fs_type
== ventoy_fs_exfat
)
2294 grub_fat_get_file_chunk(start
, file
, chunklist
);
2296 else if (fs_type
== ventoy_fs_ext
)
2298 grub_ext_get_file_chunk(start
, file
, chunklist
);
2302 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2303 file
->read_hook_data
= chunklist
;
2305 for (size
= file
->size
; size
> 0; size
-= read
)
2307 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2308 grub_file_read(file
, NULL
, read
);
2311 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2313 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2314 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2317 if (ventoy_fs_udf
== fs_type
)
2319 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2321 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2322 chunklist
->chunk
[i
].img_start_sector
= sector
;
2323 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2329 len
= (int)grub_strlen(file
->name
);
2330 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2331 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2332 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2333 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2335 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2337 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2347 chunklist
->chunk
[i
].img_start_sector
= sector
;
2348 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2356 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2360 grub_disk_addr_t start
;
2365 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2368 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2371 g_conf_replace_node
= NULL
;
2372 g_conf_replace_offset
= 0;
2374 if (g_img_chunk_list
.chunk
)
2376 grub_free(g_img_chunk_list
.chunk
);
2379 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2381 grub_file_close(file
);
2382 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2385 /* get image chunk data */
2386 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2387 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2388 if (NULL
== g_img_chunk_list
.chunk
)
2390 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2393 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2394 g_img_chunk_list
.cur_chunk
= 0;
2396 start
= file
->device
->disk
->partition
->start
;
2398 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2400 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2401 grub_file_close(file
);
2405 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2408 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2409 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2412 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2414 grub_uint64_t offset
= 0;
2415 grub_uint32_t align
= 0;
2416 grub_file_t file
= NULL
;
2417 conf_replace
*node
= NULL
;
2423 debug("select conf replace argc:%d\n", argc
);
2430 node
= ventoy_plugin_find_conf_replace(args
[1]);
2433 debug("Conf replace not found for %s\n", args
[1]);
2437 debug("Find conf replace for %s\n", args
[1]);
2439 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2442 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2446 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2447 grub_file_close(file
);
2449 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2452 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2456 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2458 if (align
> vtoy_max_replace_file_size
)
2460 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2464 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2465 g_conf_replace_new_len
= (int)file
->size
;
2466 g_conf_replace_new_len_align
= align
;
2468 g_conf_replace_node
= node
;
2469 g_conf_replace_offset
= offset
+ 2;
2471 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2476 grub_file_close(file
);
2478 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2481 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2486 char configfile
[128];
2487 install_template
*node
= NULL
;
2493 debug("select auto installation argc:%d\n", argc
);
2500 node
= ventoy_plugin_find_install_template(args
[0]);
2503 debug("Auto install template not found for %s\n", args
[0]);
2507 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2509 node
->cursel
= node
->autosel
- 1;
2510 debug("Auto install template auto select %d\n", node
->autosel
);
2514 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2520 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2521 " echo %s\n}\n", "123");
2523 for (i
= 0; i
< node
->templatenum
; i
++)
2525 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2527 node
->templatepath
[i
].path
);
2530 g_ventoy_menu_esc
= 1;
2531 g_ventoy_suppress_esc
= 1;
2533 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2534 grub_script_execute_sourcecode(configfile
);
2536 g_ventoy_menu_esc
= 0;
2537 g_ventoy_suppress_esc
= 0;
2541 node
->cursel
= g_ventoy_last_entry
- 1;
2543 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2546 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2551 char configfile
[128];
2552 persistence_config
*node
;
2558 debug("select persistence argc:%d\n", argc
);
2565 node
= ventoy_plugin_find_persistent(args
[0]);
2568 debug("Persistence image not found for %s\n", args
[0]);
2572 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2574 node
->cursel
= node
->autosel
- 1;
2575 debug("Persistence image auto select %d\n", node
->autosel
);
2579 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2585 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2586 " echo %s\n}\n", "123");
2588 for (i
= 0; i
< node
->backendnum
; i
++)
2590 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2592 node
->backendpath
[i
].path
);
2596 g_ventoy_menu_esc
= 1;
2597 g_ventoy_suppress_esc
= 1;
2599 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2600 grub_script_execute_sourcecode(configfile
);
2602 g_ventoy_menu_esc
= 0;
2603 g_ventoy_suppress_esc
= 0;
2607 node
->cursel
= g_ventoy_last_entry
- 1;
2609 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2612 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2615 ventoy_img_chunk
*cur
;
2621 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2623 cur
= g_img_chunk_list
.chunk
+ i
;
2624 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2625 cur
->img_start_sector
, cur
->img_end_sector
,
2626 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2630 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2633 #ifdef GRUB_MACHINE_EFI
2634 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2642 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2645 ulong chain_len
= 0;
2646 char *chain_data
= NULL
;
2647 char *relocator_addr
= NULL
;
2648 grub_relocator_chunk_t ch
;
2649 struct grub_relocator
*relocator
= NULL
;
2650 char envbuf
[64] = { 0 };
2661 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
2662 chain_len
= grub_strtoul(args
[1], NULL
, 10);
2664 relocator
= grub_relocator_new ();
2667 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
2671 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
2672 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
2676 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
2677 grub_relocator_unload (relocator
);
2681 relocator_addr
= get_virtual_current_address(ch
);
2683 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
2685 grub_relocator_unload (relocator
);
2687 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
2688 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
2690 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2694 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2698 ventoy_img_chunk_list chunklist
;
2703 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2706 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2709 /* get image chunk data */
2710 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2711 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2712 if (NULL
== chunklist
.chunk
)
2714 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2717 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2718 chunklist
.cur_chunk
= 0;
2720 ventoy_get_block_list(file
, &chunklist
, 0);
2722 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2724 grub_printf("########## UNSUPPORTED ###############\n");
2727 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2729 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2731 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2732 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2735 grub_printf("\n==================================\n");
2737 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2739 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2740 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2741 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2742 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2743 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2747 grub_free(chunklist
.chunk
);
2748 grub_file_close(file
);
2750 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2753 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2756 ventoy_grub_param_file_replace
*replace
= NULL
;
2764 replace
= &(g_grub_param
->file_replace
);
2765 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2767 replace
->old_name_cnt
= 0;
2768 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2770 replace
->old_name_cnt
++;
2771 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2774 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2777 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2780 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2788 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2789 grub_printf("%s", g_list_script_buf
);
2793 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2794 grub_printf("%s", g_tree_script_buf
);
2800 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2802 img_info
*cur
= g_ventoy_img_list
;
2810 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2811 grub_printf("name:<%s>\n\n", cur
->name
);
2818 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2824 ventoy_plugin_dump_injection();
2829 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2835 ventoy_plugin_dump_auto_install();
2840 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2846 ventoy_plugin_dump_persistence();
2851 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2862 if (args
[0][0] == '0')
2864 return g_ventoy_memdisk_mode
? 0 : 1;
2866 else if (args
[0][0] == '1')
2868 return g_ventoy_iso_raw
? 0 : 1;
2870 else if (args
[0][0] == '2')
2872 return g_ventoy_iso_uefi_drv
? 0 : 1;
2878 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2880 static int configfile_mode
= 0;
2881 char memfile
[128] = {0};
2888 * args[0]: 0:normal 1:configfile
2889 * args[1]: 0:list_buf 1:tree_buf
2894 debug("Invalid argc %d\n", argc
);
2898 if (args
[0][0] == '0')
2900 if (args
[1][0] == '0')
2902 grub_script_execute_sourcecode(g_list_script_buf
);
2906 grub_script_execute_sourcecode(g_tree_script_buf
);
2911 if (configfile_mode
)
2913 debug("Now already in F3 mode %d\n", configfile_mode
);
2917 if (args
[1][0] == '0')
2919 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2920 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2924 g_ventoy_last_entry
= -1;
2925 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2926 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2929 configfile_mode
= 1;
2930 grub_script_execute_sourcecode(memfile
);
2931 configfile_mode
= 0;
2937 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2948 g_ventoy_case_insensitive
= 1;
2949 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2950 g_ventoy_case_insensitive
= 0;
2956 grub_file_close(file
);
2962 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2967 const char *isopath
= NULL
;
2969 ventoy_mbr_head mbr
;
2976 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2979 isopath
= grub_env_get("vtoy_iso_part");
2982 debug("isopath is null %p\n", isopath
);
2986 debug("isopath is %s\n", isopath
);
2988 for (id
= 0; id
< 30 && (find
== 0); id
++)
2990 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2991 if (grub_strstr(isopath
, hdname
))
2993 debug("skip %s ...\n", hdname
);
2997 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2999 disk
= grub_disk_open(hdname
);
3002 debug("%s not exist\n", hdname
);
3006 grub_memset(&mbr
, 0, sizeof(mbr
));
3007 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3009 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3011 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3012 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3015 grub_env_set(args
[0], hdname
);
3019 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3023 debug("read %s failed\n", hdname
);
3026 grub_disk_close(disk
);
3032 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3043 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3046 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3049 debug("failed to open file %s\n", args
[0]);
3053 buf
= grub_malloc(len
);
3060 grub_file_read(file
, buf
, len
- 1);
3062 ventoy_get_line(buf
);
3063 ventoy_set_env(args
[1], buf
);
3067 grub_check_free(buf
);
3068 grub_file_close(file
);
3073 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3078 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3079 "0 %llu linear /dev/ventoy %llu\n",
3080 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3085 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3087 char *device_name
= NULL
;
3088 grub_device_t dev
= NULL
;
3093 g_part_list_pos
= 0;
3094 grub_env_unset("vtoy_img_part_file");
3101 device_name
= grub_file_get_device_name(args
[0]);
3104 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3108 dev
= grub_device_open(device_name
);
3111 debug("grub_device_open failed, %s\n", device_name
);
3115 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3117 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3118 grub_env_set("vtoy_img_part_file", buf
);
3122 check_free(device_name
, grub_free
);
3123 check_free(dev
, grub_device_close
);
3129 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3140 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3143 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3146 debug("failed to open file %s\n", args
[0]);
3150 buf
= grub_malloc(file
->size
+ 1);
3156 buf
[file
->size
] = 0;
3157 grub_file_read(file
, buf
, file
->size
);
3159 if (grub_strstr(buf
, args
[1]))
3166 grub_check_free(buf
);
3167 grub_file_close(file
);
3172 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3177 ventoy_iso9660_vd pvd
;
3184 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3187 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3190 debug("failed to open file %s\n", args
[0]);
3194 grub_file_seek(file
, 16 * 2048);
3195 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3196 if (len
!= sizeof(pvd
))
3198 debug("failed to read pvd %d\n", len
);
3202 grub_memset(buf
, 0, sizeof(buf
));
3203 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3204 ventoy_set_env(args
[1], buf
);
3206 grub_memset(buf
, 0, sizeof(buf
));
3207 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3208 ventoy_set_env(args
[2], buf
);
3211 grub_file_close(file
);
3216 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3227 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3230 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3233 debug("failed to open file %s\n", args
[0]);
3237 grub_memset(buf
, 0, sizeof(buf
));
3238 grub_file_seek(file
, 16 * 2048 + 813);
3239 len
= (int)grub_file_read(file
, buf
, 17);
3242 debug("failed to read create date %d\n", len
);
3246 ventoy_set_env(args
[1], buf
);
3249 grub_file_close(file
);
3254 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3260 ventoy_env_hook_root(1);
3265 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3271 ventoy_env_hook_root(0);
3276 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3283 int image_sector_size
;
3285 ventoy_chain_head
*chain
;
3286 ventoy_img_chunk
*chunk
;
3287 ventoy_os_param
*osparam
;
3288 ventoy_image_location
*location
;
3289 ventoy_image_disk_region
*region
;
3290 struct grub_acpi_table_header
*acpi
;
3299 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3301 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3307 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3309 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3311 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3315 img_chunk_num
= chain
->img_chunk_num
;
3317 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3318 datalen
= sizeof(ventoy_os_param
) + loclen
;
3320 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3321 acpi
= grub_zalloc(buflen
);
3327 /* Step1: Fill acpi table header */
3328 grub_memcpy(acpi
->signature
, "VTOY", 4);
3329 acpi
->length
= buflen
;
3331 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3332 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3334 acpi
->creator_id
[0] = 1;
3335 acpi
->creator_rev
= 1;
3337 /* Step2: Fill data */
3338 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3339 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3340 osparam
->vtoy_img_location_addr
= 0;
3341 osparam
->vtoy_img_location_len
= loclen
;
3342 osparam
->chksum
= 0;
3343 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3345 location
= (ventoy_image_location
*)(osparam
+ 1);
3346 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3347 location
->image_sector_size
= image_sector_size
;
3348 location
->disk_sector_size
= chain
->disk_sector_size
;
3349 location
->region_count
= img_chunk_num
;
3351 region
= location
->regions
;
3352 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3353 if (512 == image_sector_size
)
3355 for (i
= 0; i
< img_chunk_num
; i
++)
3357 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3358 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3359 region
->disk_start_sector
= chunk
->disk_start_sector
;
3366 for (i
= 0; i
< img_chunk_num
; i
++)
3368 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3369 region
->image_start_sector
= chunk
->img_start_sector
;
3370 region
->disk_start_sector
= chunk
->disk_start_sector
;
3376 /* Step3: Fill acpi checksum */
3378 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3380 /* load acpi table */
3381 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3382 grub_script_execute_sourcecode(cmd
);
3386 VENTOY_CMD_RETURN(0);
3389 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3395 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3396 g_ventoy_last_entry
= -1;
3401 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3407 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3412 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3414 const char *pos
= filename
+ 1;
3422 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3424 grub_strncpy((char *)data
, filename
, 128);
3435 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3438 char *device_name
= NULL
;
3439 grub_device_t dev
= NULL
;
3440 grub_fs_t fs
= NULL
;
3441 char buf
[128] = {0};
3447 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3451 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3453 device_name
= grub_file_get_device_name(args
[0]);
3456 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3460 dev
= grub_device_open(device_name
);
3463 debug("grub_device_open failed, %s\n", device_name
);
3467 fs
= grub_fs_probe(dev
);
3470 debug("grub_fs_probe failed, %s\n", device_name
);
3474 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3478 ventoy_set_env(args
[2], buf
);
3485 check_free(device_name
, grub_free
);
3486 check_free(dev
, grub_device_close
);
3491 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3501 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3502 if (!g_ventoy_part_info
)
3507 disk
= grub_disk_open(args
[0]);
3510 debug("Failed to open disk %s\n", args
[0]);
3514 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3515 grub_disk_close(disk
);
3517 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3518 dev
= grub_device_open(name
);
3521 /* make sure that we are running in a correct Ventoy device */
3522 ret
= ventoy_check_device(dev
);
3523 grub_device_close(dev
);
3534 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3537 grub_uint8_t zeroguid
[16] = {0};
3542 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3545 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3547 if (id
>= 1 && id
<= 128)
3549 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3557 if (id
>= 1 && id
<= 4)
3559 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3569 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3572 char *device_name
= NULL
;
3573 grub_device_t dev
= NULL
;
3574 grub_fs_t fs
= NULL
;
3581 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3585 device_name
= grub_file_get_device_name(args
[0]);
3588 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3592 dev
= grub_device_open(device_name
);
3595 debug("grub_device_open failed, %s\n", device_name
);
3599 fs
= grub_fs_probe(dev
);
3602 debug("grub_fs_probe failed, %s\n", device_name
);
3606 fs
->fs_label(dev
, &label
);
3609 ventoy_set_env(args
[1], label
);
3617 check_free(device_name
, grub_free
);
3618 check_free(dev
, grub_device_close
);
3623 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3627 grub_snprintf((char *)data
, 256, "%s", filename
);
3635 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3638 char *device_name
= NULL
;
3639 grub_device_t dev
= NULL
;
3640 grub_fs_t fs
= NULL
;
3641 char name
[256] ={0};
3647 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3651 device_name
= grub_file_get_device_name(args
[0]);
3654 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3658 dev
= grub_device_open(device_name
);
3661 debug("grub_device_open failed, %s\n", device_name
);
3665 fs
= grub_fs_probe(dev
);
3668 debug("grub_fs_probe failed, %s\n", device_name
);
3672 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3675 ventoy_set_env(args
[2], name
);
3682 check_free(device_name
, grub_free
);
3683 check_free(dev
, grub_device_close
);
3688 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3698 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3702 for (pos
= args
[0]; *pos
; pos
++)
3716 grub_env_set(args
[1], args
[0]);
3726 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3728 struct grub_video_mode_info info
;
3735 if (!g_video_mode_list
)
3737 ventoy_enum_video_mode();
3740 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3742 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3746 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3749 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3751 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3752 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3754 VENTOY_CMD_RETURN(0);
3757 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3759 struct grub_video_mode_info info
;
3766 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3768 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3772 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3775 grub_env_set(args
[0], buf
);
3777 VENTOY_CMD_RETURN(0);
3780 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3788 if (!g_video_mode_list
)
3793 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3794 if (id
< g_video_mode_num
)
3796 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3797 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3800 grub_env_set(args
[1], buf
);
3802 VENTOY_CMD_RETURN(0);
3805 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3807 grub_uint64_t size
= 0;
3810 char fullpath
[256] = {0};
3813 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3816 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3819 debug("grub_file_open failed <%s>\n", fullpath
);
3825 grub_file_close(file
);
3829 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3833 char fullpath
[256] = {0};
3836 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3839 file
= grub_file_open(fullpath
, type
);
3842 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3849 int ventoy_is_file_exist(const char *fmt
, ...)
3854 char buf
[256] = {0};
3856 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
3860 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3863 grub_strncpy(pos
+ len
, " ]", 2);
3865 debug("script exec %s\n", buf
);
3867 if (0 == grub_script_execute_sourcecode(buf
))
3875 int ventoy_is_dir_exist(const char *fmt
, ...)
3880 char buf
[256] = {0};
3882 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
3886 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3889 grub_strncpy(pos
+ len
, " ]", 2);
3891 debug("script exec %s\n", buf
);
3893 if (0 == grub_script_execute_sourcecode(buf
))
3901 static int ventoy_env_init(void)
3905 grub_env_set("vtdebug_flag", "");
3907 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3908 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3909 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3910 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
3912 ventoy_filt_register(0, ventoy_wrapper_open
);
3914 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3917 g_grub_param
->grub_env_get
= grub_env_get
;
3918 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3919 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3920 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3921 grub_env_set("env_param", buf
);
3922 grub_env_set("ventoy_env_param", buf
);
3923 grub_env_export("ventoy_env_param");
3929 static cmd_para ventoy_cmds
[] =
3931 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3932 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3933 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3934 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3935 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3936 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3937 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3938 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3939 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3940 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3941 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3942 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3943 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3944 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3945 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3946 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3947 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3948 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3949 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
3950 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
3952 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3953 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3954 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3955 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3956 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3957 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3959 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
3960 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
3961 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3962 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3963 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3964 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
3965 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
3966 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
3969 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3970 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
3971 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
3972 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
3973 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
3974 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
3975 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
3976 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
3977 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
3978 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
3979 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
3981 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
3982 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
3983 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
3984 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
3985 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
3986 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
3988 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3989 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3990 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
3991 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
3992 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
3993 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
3994 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
3995 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
3996 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
3997 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
3999 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
4000 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
4001 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
4002 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
4003 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
4004 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
4005 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
4007 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
4008 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
4009 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
4010 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
4013 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
4014 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
4016 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
4017 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
4018 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
4021 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4022 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4023 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4024 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4025 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4026 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4027 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4028 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4030 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4031 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4032 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4038 GRUB_MOD_INIT(ventoy
)
4041 cmd_para
*cur
= NULL
;
4045 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4047 cur
= ventoy_cmds
+ i
;
4048 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4049 cur
->summary
, cur
->description
, cur
->parser
);
4053 GRUB_MOD_FINI(ventoy
)
4057 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4059 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);