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] == '_')
1124 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1128 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
1138 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1147 img_iterator_node
*tmp
;
1148 img_iterator_node
*new_node
;
1149 img_iterator_node
*node
= (img_iterator_node
*)data
;
1151 len
= grub_strlen(filename
);
1155 if ((len
== 1 && filename
[0] == '.') ||
1156 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1161 if (!ventoy_img_name_valid(filename
, len
))
1166 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1171 if (g_plugin_image_list
)
1173 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1174 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1177 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1182 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1185 new_node
->plugin_list_index
= index
;
1186 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1188 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1191 debug("Directory %s ignored...\n", new_node
->dir
);
1192 grub_free(new_node
);
1196 new_node
->tail
= node
->tail
;
1198 new_node
->parent
= node
;
1199 if (!node
->firstchild
)
1201 node
->firstchild
= new_node
;
1204 if (g_img_iterator_tail
)
1206 g_img_iterator_tail
->next
= new_node
;
1207 g_img_iterator_tail
= new_node
;
1211 g_img_iterator_head
.next
= new_node
;
1212 g_img_iterator_tail
= new_node
;
1218 debug("Find a file %s\n", filename
);
1224 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1226 type
= img_type_iso
;
1228 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1230 type
= img_type_wim
;
1232 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1233 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1235 type
= img_type_vhd
;
1237 #ifdef GRUB_MACHINE_EFI
1238 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1240 type
= img_type_efi
;
1243 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1245 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1247 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1248 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1253 type
= img_type_img
;
1255 else if (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1257 type
= img_type_vtoy
;
1264 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1269 if (g_plugin_image_list
)
1271 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1272 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1275 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1280 img
= grub_zalloc(sizeof(img_info
));
1284 img
->plugin_list_index
= index
;
1285 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1287 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1289 img
->size
= info
->size
;
1292 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1295 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1297 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1302 if (g_ventoy_img_list
)
1304 tail
= *(node
->tail
);
1310 g_ventoy_img_list
= img
;
1313 img
->id
= g_ventoy_img_count
;
1315 if (node
&& NULL
== node
->firstiso
)
1317 node
->firstiso
= img
;
1328 *((img_info
**)(node
->tail
)) = img
;
1329 g_ventoy_img_count
++;
1331 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1332 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1335 img
->class = g_menu_class
[type
];
1337 img
->menu_prefix
= g_menu_prefix
[type
];
1339 if (img_type_iso
== type
)
1341 if (ventoy_plugin_check_memdisk(img
->path
))
1343 img
->menu_prefix
= "miso";
1347 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1354 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1356 int len
= GRUB_UINT_MAX
;
1357 const char *value
= NULL
;
1358 char name
[32] = {0};
1359 char plat
[32] = {0};
1360 char guidstr
[32] = {0};
1361 ventoy_guid guid
= VENTOY_GUID
;
1362 const char *fmt1
= NULL
;
1363 const char *fmt2
= NULL
;
1364 const char *fmt3
= NULL
;
1365 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1366 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1367 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1368 const char fmtcode
[]={
1369 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1370 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1371 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1372 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1373 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1374 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1377 grub_memset(name
, 0, sizeof(name
));
1378 puint
[0] = grub_swap_bytes32(0x56454e54);
1379 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1380 puint
[2] = grub_swap_bytes32(0x45525349);
1381 puint
[1] = grub_swap_bytes32(0x4f595f56);
1382 value
= ventoy_get_env(name
);
1384 grub_memset(name
, 0, sizeof(name
));
1385 puint
[1] = grub_swap_bytes32(0x5f544f50);
1386 puint
[0] = grub_swap_bytes32(0x56544c45);
1387 fmt1
= ventoy_get_env(name
);
1393 grub_memset(name
, 0, sizeof(name
));
1394 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1395 puint
[0] = grub_swap_bytes32(0x56544c45);
1396 fmt2
= ventoy_get_env(name
);
1398 grub_memset(name
, 0, sizeof(name
));
1399 puint
[1] = grub_swap_bytes32(0x5f434c52);
1400 puint
[0] = grub_swap_bytes32(0x56544c45);
1401 fmt3
= ventoy_get_env(name
);
1403 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1405 #if defined (GRUB_MACHINE_EFI)
1406 puint2
[0] = grub_swap_bytes32(0x55454649);
1408 puint2
[0] = grub_swap_bytes32(0x42494f53);
1411 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1412 #pragma GCC diagnostic push
1413 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1414 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1415 fmt1
? fmt1
: fmtdata
,
1416 fmt2
? fmt2
: fmtdata
+ 4,
1417 value
? value
: "", plat
, guidstr
,
1418 fmt3
? fmt3
: fmtdata
+ 6);
1419 #pragma GCC diagnostic pop
1421 grub_memset(name
, 0, sizeof(name
));
1422 puint
[0] = grub_swap_bytes32(0x76746f79);
1423 puint
[2] = grub_swap_bytes32(0x656e7365);
1424 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1425 ventoy_set_env(name
, guidstr
);
1430 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1432 img_info
*minimg
= NULL
;
1433 img_info
*img
= (img_info
*)(node
->firstiso
);
1435 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1437 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1452 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1454 img_iterator_node
*Minchild
= NULL
;
1455 img_iterator_node
*child
= node
->firstchild
;
1457 while (child
&& child
->parent
== node
)
1459 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1463 child
= child
->next
;
1468 Minchild
->select
= 1;
1474 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1477 img_info
*img
= NULL
;
1478 const char *dir_class
= NULL
;
1479 const char *dir_alias
= NULL
;
1480 img_iterator_node
*child
= NULL
;
1482 if (node
->isocnt
== 0 || node
->done
== 1)
1487 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1489 offset
= node
->parent
->dirlen
;
1492 if (node
== &g_img_iterator_head
)
1494 if (g_default_menu_mode
== 0)
1496 if (g_tree_view_menu_style
== 0)
1498 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1499 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1500 " echo 'return ...' \n"
1505 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1506 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1514 node
->dir
[node
->dirlen
- 1] = 0;
1515 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1518 dir_class
= "vtoydir";
1521 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1524 if (g_tree_view_menu_style
== 0)
1526 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1527 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1528 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1532 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1533 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1534 dir_alias
, dir_class
, node
->dir
+ offset
);
1539 dir_alias
= node
->dir
+ offset
;
1541 if (g_tree_view_menu_style
== 0)
1543 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1544 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1545 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
1549 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1550 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
1551 dir_alias
, dir_class
, node
->dir
+ offset
);
1555 if (g_tree_view_menu_style
== 0)
1557 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1558 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1559 " echo 'return ...' \n"
1564 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1565 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
1571 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1573 ventoy_dynamic_tree_menu(child
);
1576 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1578 if (g_tree_view_menu_style
== 0)
1580 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1581 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1584 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1585 img
->unsupport
? "[***********] " : "",
1586 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1588 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1592 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1593 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1596 img
->unsupport
? "[***********] " : "",
1597 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1599 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1603 if (node
!= &g_img_iterator_head
)
1605 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1612 int ventoy_check_device_result(int ret
)
1616 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
1617 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
1618 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
1622 grub_printf(VTOY_WARNING
"\n");
1623 grub_printf(VTOY_WARNING
"\n");
1624 grub_printf(VTOY_WARNING
"\n\n\n");
1626 grub_printf("This is NOT a standard Ventoy device and is NOT supported.\n\n");
1627 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1629 grub_printf("\n\nWill exit after 10 seconds ...... ");
1637 int ventoy_check_device(grub_device_t dev
)
1640 grub_uint64_t offset
;
1645 struct grub_partition
*partition
;
1647 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1649 return ventoy_check_device_result(1 | 0x1000);
1652 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
1653 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
1654 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_64", dev
->disk
->name
))
1656 return ventoy_check_device_result(2 | 0x1000);
1659 /* We must have partition 2 */
1660 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1663 return ventoy_check_device_result(3 | 0x1000);
1666 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
1668 grub_file_close(file
);
1669 return ventoy_check_device_result(4 | 0x1000);
1672 partition
= dev
->disk
->partition
;
1673 if (partition
->number
!= 0 || partition
->start
!= 2048)
1675 return ventoy_check_device_result(5);
1678 offset
= partition
->start
+ partition
->len
;
1679 partition
= file
->device
->disk
->partition
;
1680 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1682 grub_file_close(file
);
1683 return ventoy_check_device_result(6);
1685 grub_file_close(file
);
1687 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1688 dev2
= grub_device_open(devname
);
1691 return ventoy_check_device_result(7);
1694 fs
= grub_fs_probe(dev2
);
1697 grub_device_close(dev2
);
1698 return ventoy_check_device_result(8);
1701 fs
->fs_label(dev2
, &label
);
1702 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1704 grub_device_close(dev2
);
1705 return ventoy_check_device_result(9);
1708 grub_device_close(dev2
);
1709 return ventoy_check_device_result(0);
1712 static int ventoy_set_default_menu(void)
1718 const char *strdata
= NULL
;
1719 img_info
*cur
= NULL
;
1720 img_info
*default_node
= NULL
;
1721 const char *default_image
= NULL
;
1723 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1724 if (default_image
&& default_image
[0] == '/')
1726 img_len
= grub_strlen(default_image
);
1728 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1730 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1742 if (0 == g_default_menu_mode
)
1744 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1748 def
= grub_strdup(default_image
);
1754 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
1756 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1757 if (strdata
&& strdata
[0] == '/')
1759 pos
= def
+ grub_strlen(strdata
);
1770 while ((end
= grub_strchr(pos
, '/')) != NULL
)
1773 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
1777 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%d'\n", default_node
->id
);
1785 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1789 grub_device_t dev
= NULL
;
1790 img_info
*cur
= NULL
;
1791 img_info
*tail
= NULL
;
1792 const char *strdata
= NULL
;
1793 char *device_name
= NULL
;
1795 img_iterator_node
*node
= NULL
;
1796 img_iterator_node
*tmp
= NULL
;
1802 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1805 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1807 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1810 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1811 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1813 g_filt_dot_underscore_file
= 1;
1816 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
1817 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1819 g_sort_case_sensitive
= 1;
1822 device_name
= grub_file_get_device_name(args
[0]);
1828 g_enum_dev
= dev
= grub_device_open(device_name
);
1834 g_enum_fs
= fs
= grub_fs_probe(dev
);
1840 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1842 debug("unsupported fs:<%s>\n", fs
->name
);
1843 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1847 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1849 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1850 if (strdata
&& strdata
[0] == '1')
1852 g_default_menu_mode
= 1;
1855 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1857 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1859 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1860 if (strdata
&& strdata
[0] == '/')
1862 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1863 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1865 g_img_iterator_head
.dir
[len
++] = '/';
1867 g_img_iterator_head
.dirlen
= len
;
1871 g_img_iterator_head
.dirlen
= 1;
1872 grub_strcpy(g_img_iterator_head
.dir
, "/");
1875 g_img_iterator_head
.tail
= &tail
;
1877 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1879 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1882 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
1883 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1885 g_tree_view_menu_style
= 1;
1888 ventoy_set_default_menu();
1890 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1892 ventoy_dynamic_tree_menu(node
);
1896 node
= g_img_iterator_head
.next
;
1904 /* sort image list by image name */
1905 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1907 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1909 if (ventoy_cmp_img(cur
, tail
) > 0)
1911 ventoy_swap_img(cur
, tail
);
1916 if (g_default_menu_mode
== 1)
1918 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1919 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1920 " echo 'return ...' \n"
1924 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1926 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1927 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1930 cur
->unsupport
? "[***********] " : "",
1931 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1933 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1936 g_tree_script_buf
[g_tree_script_pos
] = 0;
1937 g_list_script_buf
[g_list_script_pos
] = 0;
1939 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1940 grub_env_set(args
[1], buf
);
1944 check_free(device_name
, grub_free
);
1945 check_free(dev
, grub_device_close
);
1947 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1951 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1953 img_info
*next
= NULL
;
1954 img_info
*cur
= g_ventoy_img_list
;
1967 g_ventoy_img_list
= NULL
;
1968 g_ventoy_img_count
= 0;
1970 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1973 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1976 img_info
*cur
= g_ventoy_img_list
;
1980 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1982 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1985 img_id
= grub_strtol(args
[0], NULL
, 10);
1986 if (img_id
>= g_ventoy_img_count
)
1988 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1991 debug("Find image %ld name \n", img_id
);
1993 while (cur
&& img_id
> 0)
2001 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2004 debug("image name is %s\n", cur
->name
);
2006 grub_env_set(args
[1], cur
->name
);
2008 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2011 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2016 const char *id
= NULL
;
2017 img_info
*cur
= g_ventoy_img_list
;
2021 if (argc
< 1 || argc
> 2)
2023 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2026 id
= grub_env_get("chosen");
2028 pos
= grub_strstr(id
, "VID_");
2031 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
2035 img_id
= (int)grub_strtoul(id
, NULL
, 10);
2040 if (img_id
== cur
->id
)
2049 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2052 grub_env_set(args
[0], cur
->path
);
2056 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2057 grub_env_set(args
[1], value
);
2060 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2063 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2070 device_name
= grub_file_get_device_name(filename
);
2082 pos2
= grub_strstr(pos
, ",");
2085 pos2
= grub_strstr(pos
, ")");
2093 disk
= grub_disk_open(pos
);
2096 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2097 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2098 grub_disk_close(disk
);
2105 grub_free(device_name
);
2109 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2111 eltorito_descriptor desc
;
2113 grub_memset(&desc
, 0, sizeof(desc
));
2114 grub_file_seek(file
, 17 * 2048);
2115 grub_file_read(file
, &desc
, sizeof(desc
));
2117 if (desc
.type
!= 0 || desc
.version
!= 1)
2122 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2123 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2131 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2135 grub_uint8_t buf
[512];
2137 grub_file_seek(file
, sector
* 2048);
2138 grub_file_read(file
, buf
, sizeof(buf
));
2140 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2142 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2146 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2151 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2153 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2155 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2159 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2161 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2166 debug("%s does not contain efi eltorito\n", file
->name
);
2170 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2173 const char *fs
= NULL
;
2174 const char *cdprompt
= NULL
;
2176 grub_uint8_t chksum
= 0;
2179 disk
= file
->device
->disk
;
2180 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2182 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2183 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2184 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2186 pos
= grub_strstr(file
->name
, "/");
2192 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2194 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2196 param
->vtoy_img_size
= file
->size
;
2198 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2199 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2201 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2203 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2204 param
->vtoy_reserved
[4] = 0;
2205 if (g_ventoy_chain_type
== 1) /* Windows */
2207 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2208 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2210 param
->vtoy_reserved
[4] = 1;
2214 fs
= ventoy_get_env("ventoy_fs_probe");
2215 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2217 param
->vtoy_reserved
[3] = 1;
2220 /* calculate checksum */
2221 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2223 chksum
+= *((grub_uint8_t
*)param
+ i
);
2225 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2230 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2232 grub_uint32_t i
= 0;
2233 grub_uint64_t total
= 0;
2234 ventoy_img_chunk
*chunk
= NULL
;
2236 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2238 chunk
= chunklist
->chunk
+ i
;
2240 if (chunk
->disk_start_sector
<= start
)
2242 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2246 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2249 if (total
!= ((file
->size
+ 511) / 512))
2251 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
2258 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2262 grub_uint32_t i
= 0;
2263 grub_uint32_t sector
= 0;
2264 grub_uint32_t count
= 0;
2265 grub_off_t size
= 0;
2266 grub_off_t read
= 0;
2268 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2269 if (fs_type
== ventoy_fs_exfat
)
2271 grub_fat_get_file_chunk(start
, file
, chunklist
);
2273 else if (fs_type
== ventoy_fs_ext
)
2275 grub_ext_get_file_chunk(start
, file
, chunklist
);
2279 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2280 file
->read_hook_data
= chunklist
;
2282 for (size
= file
->size
; size
> 0; size
-= read
)
2284 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2285 grub_file_read(file
, NULL
, read
);
2288 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2290 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2291 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2294 if (ventoy_fs_udf
== fs_type
)
2296 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2298 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2299 chunklist
->chunk
[i
].img_start_sector
= sector
;
2300 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2306 len
= (int)grub_strlen(file
->name
);
2307 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2308 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2309 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2310 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2312 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2314 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2324 chunklist
->chunk
[i
].img_start_sector
= sector
;
2325 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2333 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2337 grub_disk_addr_t start
;
2342 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2345 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2348 g_conf_replace_node
= NULL
;
2349 g_conf_replace_offset
= 0;
2351 if (g_img_chunk_list
.chunk
)
2353 grub_free(g_img_chunk_list
.chunk
);
2356 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2358 grub_file_close(file
);
2359 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2362 /* get image chunk data */
2363 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2364 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2365 if (NULL
== g_img_chunk_list
.chunk
)
2367 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2370 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2371 g_img_chunk_list
.cur_chunk
= 0;
2373 start
= file
->device
->disk
->partition
->start
;
2375 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2377 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2378 grub_file_close(file
);
2382 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2385 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2386 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2389 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2391 grub_uint64_t offset
= 0;
2392 grub_uint32_t align
= 0;
2393 grub_file_t file
= NULL
;
2394 conf_replace
*node
= NULL
;
2400 debug("select conf replace argc:%d\n", argc
);
2407 node
= ventoy_plugin_find_conf_replace(args
[1]);
2410 debug("Conf replace not found for %s\n", args
[1]);
2414 debug("Find conf replace for %s\n", args
[1]);
2416 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2419 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2423 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2424 grub_file_close(file
);
2426 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2429 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2433 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2435 if (align
> vtoy_max_replace_file_size
)
2437 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2441 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2442 g_conf_replace_new_len
= (int)file
->size
;
2443 g_conf_replace_new_len_align
= align
;
2445 g_conf_replace_node
= node
;
2446 g_conf_replace_offset
= offset
+ 2;
2448 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2453 grub_file_close(file
);
2455 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2458 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2463 char configfile
[128];
2464 install_template
*node
= NULL
;
2470 debug("select auto installation argc:%d\n", argc
);
2477 node
= ventoy_plugin_find_install_template(args
[0]);
2480 debug("Auto install template not found for %s\n", args
[0]);
2484 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2486 node
->cursel
= node
->autosel
- 1;
2487 debug("Auto install template auto select %d\n", node
->autosel
);
2491 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2497 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2498 " echo %s\n}\n", "123");
2500 for (i
= 0; i
< node
->templatenum
; i
++)
2502 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2504 node
->templatepath
[i
].path
);
2507 g_ventoy_menu_esc
= 1;
2508 g_ventoy_suppress_esc
= 1;
2510 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2511 grub_script_execute_sourcecode(configfile
);
2513 g_ventoy_menu_esc
= 0;
2514 g_ventoy_suppress_esc
= 0;
2518 node
->cursel
= g_ventoy_last_entry
- 1;
2520 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2523 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2528 char configfile
[128];
2529 persistence_config
*node
;
2535 debug("select persistence argc:%d\n", argc
);
2542 node
= ventoy_plugin_find_persistent(args
[0]);
2545 debug("Persistence image not found for %s\n", args
[0]);
2549 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2551 node
->cursel
= node
->autosel
- 1;
2552 debug("Persistence image auto select %d\n", node
->autosel
);
2556 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2562 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2563 " echo %s\n}\n", "123");
2565 for (i
= 0; i
< node
->backendnum
; i
++)
2567 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2569 node
->backendpath
[i
].path
);
2573 g_ventoy_menu_esc
= 1;
2574 g_ventoy_suppress_esc
= 1;
2576 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2577 grub_script_execute_sourcecode(configfile
);
2579 g_ventoy_menu_esc
= 0;
2580 g_ventoy_suppress_esc
= 0;
2584 node
->cursel
= g_ventoy_last_entry
- 1;
2586 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2589 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2592 ventoy_img_chunk
*cur
;
2598 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2600 cur
= g_img_chunk_list
.chunk
+ i
;
2601 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2602 cur
->img_start_sector
, cur
->img_end_sector
,
2603 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2607 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2610 #ifdef GRUB_MACHINE_EFI
2611 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2619 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2622 ulong chain_len
= 0;
2623 char *chain_data
= NULL
;
2624 char *relocator_addr
= NULL
;
2625 grub_relocator_chunk_t ch
;
2626 struct grub_relocator
*relocator
= NULL
;
2627 char envbuf
[64] = { 0 };
2638 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
2639 chain_len
= grub_strtoul(args
[1], NULL
, 10);
2641 relocator
= grub_relocator_new ();
2644 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
2648 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
2649 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
2653 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
2654 grub_relocator_unload (relocator
);
2658 relocator_addr
= get_virtual_current_address(ch
);
2660 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
2662 grub_relocator_unload (relocator
);
2664 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
2665 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
2667 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2671 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2675 ventoy_img_chunk_list chunklist
;
2680 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2683 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2686 /* get image chunk data */
2687 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2688 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2689 if (NULL
== chunklist
.chunk
)
2691 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2694 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2695 chunklist
.cur_chunk
= 0;
2697 ventoy_get_block_list(file
, &chunklist
, 0);
2699 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2701 grub_printf("########## UNSUPPORTED ###############\n");
2704 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2706 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2708 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2709 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2712 grub_printf("\n==================================\n");
2714 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2716 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2717 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2718 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2719 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2720 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2724 grub_free(chunklist
.chunk
);
2725 grub_file_close(file
);
2727 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2730 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2733 ventoy_grub_param_file_replace
*replace
= NULL
;
2741 replace
= &(g_grub_param
->file_replace
);
2742 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2744 replace
->old_name_cnt
= 0;
2745 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2747 replace
->old_name_cnt
++;
2748 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2751 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2754 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2757 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2765 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2766 grub_printf("%s", g_list_script_buf
);
2770 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2771 grub_printf("%s", g_tree_script_buf
);
2777 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2779 img_info
*cur
= g_ventoy_img_list
;
2787 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
2788 grub_printf("name:<%s>\n\n", cur
->name
);
2795 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2801 ventoy_plugin_dump_injection();
2806 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2812 ventoy_plugin_dump_auto_install();
2817 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2823 ventoy_plugin_dump_persistence();
2828 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2839 if (args
[0][0] == '0')
2841 return g_ventoy_memdisk_mode
? 0 : 1;
2843 else if (args
[0][0] == '1')
2845 return g_ventoy_iso_raw
? 0 : 1;
2847 else if (args
[0][0] == '2')
2849 return g_ventoy_iso_uefi_drv
? 0 : 1;
2855 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2857 static int configfile_mode
= 0;
2858 char memfile
[128] = {0};
2865 * args[0]: 0:normal 1:configfile
2866 * args[1]: 0:list_buf 1:tree_buf
2871 debug("Invalid argc %d\n", argc
);
2875 if (args
[0][0] == '0')
2877 if (args
[1][0] == '0')
2879 grub_script_execute_sourcecode(g_list_script_buf
);
2883 grub_script_execute_sourcecode(g_tree_script_buf
);
2888 if (configfile_mode
)
2890 debug("Now already in F3 mode %d\n", configfile_mode
);
2894 if (args
[1][0] == '0')
2896 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2897 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2901 g_ventoy_last_entry
= -1;
2902 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2903 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2906 configfile_mode
= 1;
2907 grub_script_execute_sourcecode(memfile
);
2908 configfile_mode
= 0;
2914 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2925 g_ventoy_case_insensitive
= 1;
2926 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2927 g_ventoy_case_insensitive
= 0;
2933 grub_file_close(file
);
2939 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2944 const char *isopath
= NULL
;
2946 ventoy_mbr_head mbr
;
2953 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2956 isopath
= grub_env_get("vtoy_iso_part");
2959 debug("isopath is null %p\n", isopath
);
2963 debug("isopath is %s\n", isopath
);
2965 for (id
= 0; id
< 30 && (find
== 0); id
++)
2967 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2968 if (grub_strstr(isopath
, hdname
))
2970 debug("skip %s ...\n", hdname
);
2974 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2976 disk
= grub_disk_open(hdname
);
2979 debug("%s not exist\n", hdname
);
2983 grub_memset(&mbr
, 0, sizeof(mbr
));
2984 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2986 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2988 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2989 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2992 grub_env_set(args
[0], hdname
);
2996 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3000 debug("read %s failed\n", hdname
);
3003 grub_disk_close(disk
);
3009 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3020 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3023 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3026 debug("failed to open file %s\n", args
[0]);
3030 buf
= grub_malloc(len
);
3037 grub_file_read(file
, buf
, len
- 1);
3039 ventoy_get_line(buf
);
3040 ventoy_set_env(args
[1], buf
);
3044 grub_check_free(buf
);
3045 grub_file_close(file
);
3050 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3055 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3056 "0 %llu linear /dev/ventoy %llu\n",
3057 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3062 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3064 char *device_name
= NULL
;
3065 grub_device_t dev
= NULL
;
3070 g_part_list_pos
= 0;
3071 grub_env_unset("vtoy_img_part_file");
3078 device_name
= grub_file_get_device_name(args
[0]);
3081 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3085 dev
= grub_device_open(device_name
);
3088 debug("grub_device_open failed, %s\n", device_name
);
3092 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
3094 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3095 grub_env_set("vtoy_img_part_file", buf
);
3099 check_free(device_name
, grub_free
);
3100 check_free(dev
, grub_device_close
);
3106 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3117 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3120 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3123 debug("failed to open file %s\n", args
[0]);
3127 buf
= grub_malloc(file
->size
+ 1);
3133 buf
[file
->size
] = 0;
3134 grub_file_read(file
, buf
, file
->size
);
3136 if (grub_strstr(buf
, args
[1]))
3143 grub_check_free(buf
);
3144 grub_file_close(file
);
3149 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3154 ventoy_iso9660_vd pvd
;
3161 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
3164 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3167 debug("failed to open file %s\n", args
[0]);
3171 grub_file_seek(file
, 16 * 2048);
3172 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3173 if (len
!= sizeof(pvd
))
3175 debug("failed to read pvd %d\n", len
);
3179 grub_memset(buf
, 0, sizeof(buf
));
3180 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3181 ventoy_set_env(args
[1], buf
);
3183 grub_memset(buf
, 0, sizeof(buf
));
3184 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3185 ventoy_set_env(args
[2], buf
);
3188 grub_file_close(file
);
3193 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3204 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3207 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3210 debug("failed to open file %s\n", args
[0]);
3214 grub_memset(buf
, 0, sizeof(buf
));
3215 grub_file_seek(file
, 16 * 2048 + 813);
3216 len
= (int)grub_file_read(file
, buf
, 17);
3219 debug("failed to read create date %d\n", len
);
3223 ventoy_set_env(args
[1], buf
);
3226 grub_file_close(file
);
3231 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3237 ventoy_env_hook_root(1);
3242 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3248 ventoy_env_hook_root(0);
3253 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3260 int image_sector_size
;
3262 ventoy_chain_head
*chain
;
3263 ventoy_img_chunk
*chunk
;
3264 ventoy_os_param
*osparam
;
3265 ventoy_image_location
*location
;
3266 ventoy_image_disk_region
*region
;
3267 struct grub_acpi_table_header
*acpi
;
3276 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3278 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3284 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3286 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3288 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3292 img_chunk_num
= chain
->img_chunk_num
;
3294 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3295 datalen
= sizeof(ventoy_os_param
) + loclen
;
3297 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3298 acpi
= grub_zalloc(buflen
);
3304 /* Step1: Fill acpi table header */
3305 grub_memcpy(acpi
->signature
, "VTOY", 4);
3306 acpi
->length
= buflen
;
3308 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3309 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3311 acpi
->creator_id
[0] = 1;
3312 acpi
->creator_rev
= 1;
3314 /* Step2: Fill data */
3315 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3316 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3317 osparam
->vtoy_img_location_addr
= 0;
3318 osparam
->vtoy_img_location_len
= loclen
;
3319 osparam
->chksum
= 0;
3320 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3322 location
= (ventoy_image_location
*)(osparam
+ 1);
3323 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3324 location
->image_sector_size
= image_sector_size
;
3325 location
->disk_sector_size
= chain
->disk_sector_size
;
3326 location
->region_count
= img_chunk_num
;
3328 region
= location
->regions
;
3329 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3330 if (512 == image_sector_size
)
3332 for (i
= 0; i
< img_chunk_num
; i
++)
3334 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3335 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3336 region
->disk_start_sector
= chunk
->disk_start_sector
;
3343 for (i
= 0; i
< img_chunk_num
; i
++)
3345 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3346 region
->image_start_sector
= chunk
->img_start_sector
;
3347 region
->disk_start_sector
= chunk
->disk_start_sector
;
3353 /* Step3: Fill acpi checksum */
3355 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3357 /* load acpi table */
3358 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3359 grub_script_execute_sourcecode(cmd
);
3363 VENTOY_CMD_RETURN(0);
3366 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3372 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3373 g_ventoy_last_entry
= -1;
3378 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3384 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
3389 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3391 const char *pos
= filename
+ 1;
3399 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
3401 grub_strncpy((char *)data
, filename
, 128);
3412 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3415 char *device_name
= NULL
;
3416 grub_device_t dev
= NULL
;
3417 grub_fs_t fs
= NULL
;
3418 char buf
[128] = {0};
3424 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
3428 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
3430 device_name
= grub_file_get_device_name(args
[0]);
3433 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3437 dev
= grub_device_open(device_name
);
3440 debug("grub_device_open failed, %s\n", device_name
);
3444 fs
= grub_fs_probe(dev
);
3447 debug("grub_fs_probe failed, %s\n", device_name
);
3451 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
3455 ventoy_set_env(args
[2], buf
);
3462 check_free(device_name
, grub_free
);
3463 check_free(dev
, grub_device_close
);
3468 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3478 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
3479 if (!g_ventoy_part_info
)
3484 disk
= grub_disk_open(args
[0]);
3487 debug("Failed to open disk %s\n", args
[0]);
3491 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
3492 grub_disk_close(disk
);
3494 grub_snprintf(name
, sizeof(name
), "%s,1", args
[0]);
3495 dev
= grub_device_open(name
);
3498 /* make sure that we are running in a correct Ventoy device */
3499 ret
= ventoy_check_device(dev
);
3500 grub_device_close(dev
);
3511 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3514 grub_uint8_t zeroguid
[16] = {0};
3519 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3522 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
3524 if (id
>= 1 && id
<= 128)
3526 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
3534 if (id
>= 1 && id
<= 4)
3536 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
3546 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3549 char *device_name
= NULL
;
3550 grub_device_t dev
= NULL
;
3551 grub_fs_t fs
= NULL
;
3558 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
3562 device_name
= grub_file_get_device_name(args
[0]);
3565 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3569 dev
= grub_device_open(device_name
);
3572 debug("grub_device_open failed, %s\n", device_name
);
3576 fs
= grub_fs_probe(dev
);
3579 debug("grub_fs_probe failed, %s\n", device_name
);
3583 fs
->fs_label(dev
, &label
);
3586 ventoy_set_env(args
[1], label
);
3594 check_free(device_name
, grub_free
);
3595 check_free(dev
, grub_device_close
);
3600 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3604 grub_snprintf((char *)data
, 256, "%s", filename
);
3612 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3615 char *device_name
= NULL
;
3616 grub_device_t dev
= NULL
;
3617 grub_fs_t fs
= NULL
;
3618 char name
[256] ={0};
3624 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3628 device_name
= grub_file_get_device_name(args
[0]);
3631 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3635 dev
= grub_device_open(device_name
);
3638 debug("grub_device_open failed, %s\n", device_name
);
3642 fs
= grub_fs_probe(dev
);
3645 debug("grub_fs_probe failed, %s\n", device_name
);
3649 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3652 ventoy_set_env(args
[2], name
);
3659 check_free(device_name
, grub_free
);
3660 check_free(dev
, grub_device_close
);
3665 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3675 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3679 for (pos
= args
[0]; *pos
; pos
++)
3693 grub_env_set(args
[1], args
[0]);
3703 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3705 struct grub_video_mode_info info
;
3712 if (!g_video_mode_list
)
3714 ventoy_enum_video_mode();
3717 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3719 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
3723 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
3726 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
3728 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
3729 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
3731 VENTOY_CMD_RETURN(0);
3734 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3736 struct grub_video_mode_info info
;
3743 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
3745 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
3749 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
3752 grub_env_set(args
[0], buf
);
3754 VENTOY_CMD_RETURN(0);
3757 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3765 if (!g_video_mode_list
)
3770 id
= (int)grub_strtoul(args
[0], NULL
, 10);
3771 if (id
< g_video_mode_num
)
3773 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
3774 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
3777 grub_env_set(args
[1], buf
);
3779 VENTOY_CMD_RETURN(0);
3782 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3784 grub_uint64_t size
= 0;
3787 char fullpath
[256] = {0};
3790 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3793 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3796 debug("grub_file_open failed <%s>\n", fullpath
);
3802 grub_file_close(file
);
3806 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3810 char fullpath
[256] = {0};
3813 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3816 file
= grub_file_open(fullpath
, type
);
3819 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3826 int ventoy_is_file_exist(const char *fmt
, ...)
3831 char buf
[256] = {0};
3833 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
3837 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3840 grub_strncpy(pos
+ len
, " ]", 2);
3842 debug("script exec %s\n", buf
);
3844 if (0 == grub_script_execute_sourcecode(buf
))
3852 int ventoy_is_dir_exist(const char *fmt
, ...)
3857 char buf
[256] = {0};
3859 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
3863 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3866 grub_strncpy(pos
+ len
, " ]", 2);
3868 debug("script exec %s\n", buf
);
3870 if (0 == grub_script_execute_sourcecode(buf
))
3878 static int ventoy_env_init(void)
3882 grub_env_set("vtdebug_flag", "");
3884 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3885 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3886 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3887 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
3889 ventoy_filt_register(0, ventoy_wrapper_open
);
3891 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3894 g_grub_param
->grub_env_get
= grub_env_get
;
3895 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3896 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3897 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3898 grub_env_set("env_param", buf
);
3899 grub_env_set("ventoy_env_param", buf
);
3900 grub_env_export("ventoy_env_param");
3906 static cmd_para ventoy_cmds
[] =
3908 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3909 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3910 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3911 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3912 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3913 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3914 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3915 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3916 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3917 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3918 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3919 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3920 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3921 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3922 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3923 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3924 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3925 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3926 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
3927 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
3929 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3930 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3931 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3932 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3933 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3934 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3936 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
3937 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
3938 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3939 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3940 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3941 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
3942 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
3943 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
3946 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3947 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
3948 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
3949 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
3950 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
3951 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
3952 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
3953 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
3954 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
3955 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
3956 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
3958 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
3959 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
3960 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
3961 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
3962 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
3963 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
3965 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3966 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3967 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
3968 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
3969 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
3970 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
3971 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
3972 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
3973 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
3974 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
3976 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
3977 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
3978 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
3979 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
3980 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
3981 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
3982 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
3983 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
3985 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
3986 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
3987 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
3988 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
3991 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
3992 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
3994 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
3995 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
3996 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
3999 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
4000 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
4001 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
4002 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
4003 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
4004 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
4005 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
4006 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
4008 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
4009 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
4010 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
4016 GRUB_MOD_INIT(ventoy
)
4019 cmd_para
*cur
= NULL
;
4023 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4025 cur
= ventoy_cmds
+ i
;
4026 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
4027 cur
->summary
, cur
->description
, cur
->parser
);
4031 GRUB_MOD_FINI(ventoy
)
4035 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
4037 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);