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/relocator.h>
43 #include <grub/charset.h>
44 #include <grub/ventoy.h>
45 #include "ventoy_def.h"
47 GRUB_MOD_LICENSE ("GPLv3+");
49 int g_ventoy_debug
= 0;
50 static int g_efi_os
= 0xFF;
51 initrd_info
*g_initrd_img_list
= NULL
;
52 initrd_info
*g_initrd_img_tail
= NULL
;
53 int g_initrd_img_count
= 0;
54 int g_valid_initrd_count
= 0;
55 int g_default_menu_mode
= 0;
56 int g_filt_dot_underscore_file
= 0;
57 static grub_file_t g_old_file
;
58 static int g_ventoy_last_entry_back
;
61 char g_img_swap_tmp_buf
[1024];
62 img_info g_img_swap_tmp
;
63 img_info
*g_ventoy_img_list
= NULL
;
65 int g_ventoy_img_count
= 0;
67 grub_device_t g_enum_dev
= NULL
;
68 grub_fs_t g_enum_fs
= NULL
;
69 img_iterator_node g_img_iterator_head
;
70 img_iterator_node
*g_img_iterator_tail
= NULL
;
72 grub_uint8_t g_ventoy_break_level
= 0;
73 grub_uint8_t g_ventoy_debug_level
= 0;
74 grub_uint8_t g_ventoy_chain_type
= 0;
76 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
77 grub_uint32_t g_ventoy_cpio_size
= 0;
78 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
79 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
81 ventoy_grub_param
*g_grub_param
= NULL
;
83 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
85 ventoy_img_chunk_list g_img_chunk_list
;
87 int g_wimboot_enable
= 0;
88 ventoy_img_chunk_list g_wimiso_chunk_list
;
89 char *g_wimiso_path
= NULL
;
91 int g_vhdboot_enable
= 0;
93 static char *g_tree_script_buf
= NULL
;
94 static int g_tree_script_pos
= 0;
96 static char *g_list_script_buf
= NULL
;
97 static int g_list_script_pos
= 0;
99 static char *g_part_list_buf
= NULL
;
100 static int g_part_list_pos
= 0;
102 static const char *g_menu_class
[] =
104 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd"
107 static const char *g_menu_prefix
[] =
109 "iso", "wim", "efi", "img", "vhd"
112 void ventoy_debug(const char *fmt
, ...)
116 va_start (args
, fmt
);
117 grub_vprintf (fmt
, args
);
121 void ventoy_debug_dump_guid(const char *prefix
, grub_uint8_t
*guid
)
131 for (i
= 0; i
< 16; i
++)
133 grub_printf("%02x ", guid
[i
]);
138 int ventoy_is_efi_os(void)
142 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
148 static int ventoy_get_fs_type(const char *fs
)
152 return ventoy_fs_max
;
154 else if (grub_strncmp(fs
, "exfat", 5) == 0)
156 return ventoy_fs_exfat
;
158 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
160 return ventoy_fs_ntfs
;
162 else if (grub_strncmp(fs
, "ext", 3) == 0)
164 return ventoy_fs_ext
;
166 else if (grub_strncmp(fs
, "xfs", 3) == 0)
168 return ventoy_fs_xfs
;
170 else if (grub_strncmp(fs
, "udf", 3) == 0)
172 return ventoy_fs_udf
;
174 else if (grub_strncmp(fs
, "fat", 3) == 0)
176 return ventoy_fs_fat
;
179 return ventoy_fs_max
;
182 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
201 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
203 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
207 static grub_err_t
ventoy_fs_close(grub_file_t file
)
209 grub_file_close(g_old_file
);
210 grub_free(file
->data
);
218 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
222 static struct grub_fs vtoy_fs
=
227 .fs_read
= ventoy_fs_read
,
228 .fs_close
= ventoy_fs_close
,
238 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
244 file
->data
= grub_malloc(rawFile
->size
+ 4096);
250 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
251 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
253 g_old_file
= rawFile
;
255 file
->size
= rawFile
->size
+ len
;
256 file
->device
= rawFile
->device
;
258 file
->not_easily_seekable
= 1;
263 static int ventoy_check_decimal_var(const char *name
, long *value
)
265 const char *value_str
= NULL
;
267 value_str
= grub_env_get(name
);
268 if (NULL
== value_str
)
270 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
273 if (!ventoy_is_decimal(value_str
))
275 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
278 *value
= grub_strtol(value_str
, NULL
, 10);
280 return GRUB_ERR_NONE
;
283 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
287 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
290 if (0 == grub_strcmp(args
[0], "on"))
293 grub_env_set("vtdebug_flag", "debug");
298 grub_env_set("vtdebug_flag", "");
301 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
304 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
308 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
310 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
311 grub_printf(" level:\r\n");
312 grub_printf(" 01/11: busybox / (+cat log)\r\n");
313 grub_printf(" 02/12: initrd / (+cat log)\r\n");
314 grub_printf(" 03/13: hook / (+cat log)\r\n");
316 grub_printf(" debug:\r\n");
317 grub_printf(" 0: debug is on\r\n");
318 grub_printf(" 1: debug is off\r\n");
320 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
323 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
325 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
327 g_ventoy_debug_level
= 1;
330 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
333 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
342 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
345 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
377 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
382 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
384 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
387 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
392 value_long
+= grub_strtol(args
[1], NULL
, 10);
394 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
395 grub_env_set(args
[0], buf
);
397 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
400 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
415 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
418 debug("failed to open file <%s> for udf check\n", args
[0]);
422 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
424 grub_env_set(args
[1], buf
);
426 grub_file_close(file
);
432 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
440 g_wimboot_enable
= 0;
441 grub_check_free(g_wimiso_path
);
442 grub_check_free(g_wimiso_chunk_list
.chunk
);
444 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
450 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
451 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
452 if (NULL
== g_wimiso_chunk_list
.chunk
)
454 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
457 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
458 g_wimiso_chunk_list
.cur_chunk
= 0;
460 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
462 g_wimboot_enable
= 1;
463 g_wimiso_path
= grub_strdup(args
[0]);
465 grub_file_close(file
);
470 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
476 grub_uint32_t offset
;
478 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
481 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
485 len
= (int)file
->size
;
487 data
= (char *)grub_malloc(file
->size
);
493 grub_file_read(file
, data
, file
->size
);
494 grub_file_close(file
);
496 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
497 grub_script_execute_sourcecode(exec
);
499 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
500 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
501 grub_file_close(file
);
503 grub_script_execute_sourcecode("loopback -d efiboot");
507 *direntoff
= offset
+ 2;
512 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
522 ventoy_iso9660_override
*dirent
;
531 totlen
= sizeof(ventoy_chain_head
);
533 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
535 debug("failed to load efiboot template %d\n", len
);
541 debug("efiboot template len:%d offset:%d\n", len
, offset
);
543 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
546 debug("failed to open file <%s>\n", args
[0]);
550 totlen
+= ventoy_align_2k(file
->size
);
552 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
553 dirent
->first_sector
= len
/ 2048;
554 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
555 dirent
->size
= (grub_uint32_t
)file
->size
;
556 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
558 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
560 #ifdef GRUB_MACHINE_EFI
561 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
563 data
= (char *)grub_malloc(totlen
);
566 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
568 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
569 grub_check_free(buf
);
571 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
572 grub_file_close(file
);
574 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
575 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
576 grub_env_set(name
, value
);
578 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
579 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
580 grub_env_set(name
, value
);
585 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
602 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
605 debug("failed to open file <%s>\n", args
[0]);
609 #ifdef GRUB_MACHINE_EFI
610 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
612 buf
= (char *)grub_malloc(file
->size
);
615 grub_file_read(file
, buf
, file
->size
);
617 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
618 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
619 grub_env_set(name
, value
);
621 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
622 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
623 grub_env_set(name
, value
);
625 grub_file_close(file
);
631 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
649 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
652 debug("failed to open file <%s> for udf check\n", args
[0]);
656 headlen
= sizeof(ventoy_chain_head
);
658 #ifdef GRUB_MACHINE_EFI
659 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
661 buf
= (char *)grub_malloc(headlen
+ file
->size
);
664 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
666 grub_file_read(file
, buf
+ headlen
, file
->size
);
668 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
669 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
670 grub_env_set(name
, value
);
672 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
673 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
674 grub_env_set(name
, value
);
676 grub_file_close(file
);
682 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
691 if (args
[0][0] == '1')
693 grub_iso9660_set_nojoliet(1);
697 grub_iso9660_set_nojoliet(0);
703 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
708 grub_uint8_t buf
[32];
719 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
722 debug("failed to open file <%s> for udf check\n", args
[0]);
726 for (i
= 16; i
< 32; i
++)
728 grub_file_seek(file
, i
* 2048);
729 grub_file_read(file
, buf
, sizeof(buf
));
737 grub_file_seek(file
, i
* 2048);
738 grub_file_read(file
, buf
, sizeof(buf
));
740 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
743 grub_file_seek(file
, i
* 2048);
744 grub_file_read(file
, buf
, sizeof(buf
));
746 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
747 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
753 grub_file_close(file
);
755 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
760 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
762 long value_long1
= 0;
763 long value_long2
= 0;
765 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
767 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
770 value_long1
= grub_strtol(args
[0], NULL
, 10);
771 value_long2
= grub_strtol(args
[2], NULL
, 10);
773 if (0 == grub_strcmp(args
[1], "eq"))
775 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
777 else if (0 == grub_strcmp(args
[1], "ne"))
779 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
781 else if (0 == grub_strcmp(args
[1], "gt"))
783 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
785 else if (0 == grub_strcmp(args
[1], "lt"))
787 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
789 else if (0 == grub_strcmp(args
[1], "ge"))
791 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
793 else if (0 == grub_strcmp(args
[1], "le"))
795 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
799 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
805 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
812 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
815 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
816 pos
= grub_strstr(buf
, ",");
822 grub_env_set(args
[1], buf
);
824 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
827 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
833 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
839 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
842 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
844 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
845 if (0 == grub_script_execute_sourcecode(buf
))
847 debug("file %s exist, ventoy_compatible YES\n", buf
);
848 grub_env_set("ventoy_compatible", "YES");
849 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
853 debug("file %s NOT exist\n", buf
);
857 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
858 pos
= grub_strstr(buf
, ")");
864 disk
= grub_disk_open(buf
);
867 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
868 grub_disk_close(disk
);
870 g_img_swap_tmp_buf
[703] = 0;
871 for (i
= 319; i
< 703; i
++)
873 if (g_img_swap_tmp_buf
[i
] == 'V' &&
874 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
876 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
877 grub_env_set("ventoy_compatible", "YES");
878 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
884 debug("failed to open disk <%s>\n", buf
);
887 grub_env_set("ventoy_compatible", "NO");
888 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
891 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
897 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
902 if (grub_islower(c1
))
907 if (grub_islower(c2
))
921 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
923 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
925 grub_memcpy(img1
, img2
, sizeof(img_info
));
926 img1
->next
= g_img_swap_tmp
.next
;
927 img1
->prev
= g_img_swap_tmp
.prev
;
929 g_img_swap_tmp
.next
= img2
->next
;
930 g_img_swap_tmp
.prev
= img2
->prev
;
931 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
934 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
938 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
943 for (i
= 0; i
< namelen
; i
++)
945 if (filename
[i
] == ' ' || filename
[i
] == '\t')
950 if ((grub_uint8_t
)(filename
[i
]) >= 127)
959 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
963 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
973 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
981 img_iterator_node
*tmp
;
982 img_iterator_node
*new_node
;
983 img_iterator_node
*node
= (img_iterator_node
*)data
;
985 len
= grub_strlen(filename
);
989 if ((len
== 1 && filename
[0] == '.') ||
990 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
995 if (!ventoy_img_name_valid(filename
, len
))
1000 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1005 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1008 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1010 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1013 debug("Directory %s ignored...\n", new_node
->dir
);
1014 grub_free(new_node
);
1018 new_node
->tail
= node
->tail
;
1020 new_node
->parent
= node
;
1021 if (!node
->firstchild
)
1023 node
->firstchild
= new_node
;
1026 if (g_img_iterator_tail
)
1028 g_img_iterator_tail
->next
= new_node
;
1029 g_img_iterator_tail
= new_node
;
1033 g_img_iterator_head
.next
= new_node
;
1034 g_img_iterator_tail
= new_node
;
1040 debug("Find a file %s\n", filename
);
1046 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1048 type
= img_type_iso
;
1050 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1052 type
= img_type_wim
;
1054 else if (g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1055 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx")))
1057 type
= img_type_vhd
;
1059 #ifdef GRUB_MACHINE_EFI
1060 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1062 type
= img_type_efi
;
1065 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1067 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1069 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1070 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1075 type
= img_type_img
;
1082 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1087 img
= grub_zalloc(sizeof(img_info
));
1091 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1093 for (i
= 0; i
< (int)len
; i
++)
1095 if (filename
[i
] == ' ' || filename
[i
] == '\t' || (0 == grub_isprint(filename
[i
])))
1102 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1104 img
->size
= info
->size
;
1107 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1110 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1112 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1117 if (g_ventoy_img_list
)
1119 tail
= *(node
->tail
);
1125 g_ventoy_img_list
= img
;
1128 img
->id
= g_ventoy_img_count
;
1130 if (node
&& NULL
== node
->firstiso
)
1132 node
->firstiso
= img
;
1143 *((img_info
**)(node
->tail
)) = img
;
1144 g_ventoy_img_count
++;
1146 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1147 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
1150 img
->class = g_menu_class
[type
];
1152 img
->menu_prefix
= g_menu_prefix
[type
];
1154 if (img_type_iso
== type
)
1156 if (ventoy_plugin_check_memdisk(img
->path
))
1158 img
->menu_prefix
= "miso";
1162 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1169 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1171 int len
= GRUB_UINT_MAX
;
1172 const char *value
= NULL
;
1173 char name
[32] = {0};
1174 char plat
[32] = {0};
1175 char guidstr
[32] = {0};
1176 ventoy_guid guid
= VENTOY_GUID
;
1177 const char *fmt1
= NULL
;
1178 const char *fmt2
= NULL
;
1179 const char *fmt3
= NULL
;
1180 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1181 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1182 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1183 const char fmtcode
[]={
1184 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1185 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1186 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1187 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1188 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1189 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1192 grub_memset(name
, 0, sizeof(name
));
1193 puint
[0] = grub_swap_bytes32(0x56454e54);
1194 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1195 puint
[2] = grub_swap_bytes32(0x45525349);
1196 puint
[1] = grub_swap_bytes32(0x4f595f56);
1197 value
= ventoy_get_env(name
);
1199 grub_memset(name
, 0, sizeof(name
));
1200 puint
[1] = grub_swap_bytes32(0x5f544f50);
1201 puint
[0] = grub_swap_bytes32(0x56544c45);
1202 fmt1
= ventoy_get_env(name
);
1208 grub_memset(name
, 0, sizeof(name
));
1209 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1210 puint
[0] = grub_swap_bytes32(0x56544c45);
1211 fmt2
= ventoy_get_env(name
);
1213 grub_memset(name
, 0, sizeof(name
));
1214 puint
[1] = grub_swap_bytes32(0x5f434c52);
1215 puint
[0] = grub_swap_bytes32(0x56544c45);
1216 fmt3
= ventoy_get_env(name
);
1218 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1220 #if defined (GRUB_MACHINE_EFI)
1221 puint2
[0] = grub_swap_bytes32(0x55454649);
1223 puint2
[0] = grub_swap_bytes32(0x42494f53);
1226 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1227 #pragma GCC diagnostic push
1228 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1229 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1230 fmt1
? fmt1
: fmtdata
,
1231 fmt2
? fmt2
: fmtdata
+ 4,
1232 value
? value
: "", plat
, guidstr
,
1233 fmt3
? fmt3
: fmtdata
+ 6);
1234 #pragma GCC diagnostic pop
1236 grub_memset(name
, 0, sizeof(name
));
1237 puint
[0] = grub_swap_bytes32(0x76746f79);
1238 puint
[2] = grub_swap_bytes32(0x656e7365);
1239 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1240 ventoy_set_env(name
, guidstr
);
1245 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1247 img_info
*minimg
= NULL
;
1248 img_info
*img
= (img_info
*)(node
->firstiso
);
1250 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1252 if (img
->select
== 0 && (NULL
== minimg
|| grub_strcmp(img
->name
, minimg
->name
) < 0))
1267 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1269 img_iterator_node
*Minchild
= NULL
;
1270 img_iterator_node
*child
= node
->firstchild
;
1272 while (child
&& child
->parent
== node
)
1274 if (child
->select
== 0 && (NULL
== Minchild
|| grub_strcmp(child
->dir
, Minchild
->dir
) < 0))
1278 child
= child
->next
;
1283 Minchild
->select
= 1;
1289 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1292 img_info
*img
= NULL
;
1293 const char *dir_class
= NULL
;
1294 const char *dir_alias
= NULL
;
1295 img_iterator_node
*child
= NULL
;
1297 if (node
->isocnt
== 0 || node
->done
== 1)
1302 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1304 offset
= node
->parent
->dirlen
;
1307 if (node
== &g_img_iterator_head
)
1309 if (g_default_menu_mode
== 0)
1311 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1312 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1313 " echo 'return ...' \n"
1319 node
->dir
[node
->dirlen
- 1] = 0;
1320 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1323 dir_class
= "vtoydir";
1326 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1329 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1330 "submenu \"%-10s %s\" --class=\"%s\" {\n",
1331 "DIR", dir_alias
, dir_class
);
1335 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1336 "submenu \"%-10s [%s]\" --class=\"%s\" {\n",
1337 "DIR", node
->dir
+ offset
, dir_class
);
1340 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1341 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1342 " echo 'return ...' \n"
1346 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1348 ventoy_dynamic_tree_menu(child
);
1351 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1353 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1354 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1357 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1358 img
->unsupport
? "[***********] " : "",
1359 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1361 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1364 if (node
!= &g_img_iterator_head
)
1366 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1373 int ventoy_check_device_result(int ret
)
1377 grub_snprintf(buf
, sizeof(buf
), "%d", ret
);
1378 ventoy_set_env("VTOY_CHKDEV_RESULT_STRING", buf
);
1382 grub_printf(VTOY_WARNING
"\n");
1383 grub_printf(VTOY_WARNING
"\n");
1384 grub_printf(VTOY_WARNING
"\n\n\n");
1386 grub_printf("This is NOT a standard Ventoy device and is NOT officially supported.\n\n");
1387 grub_printf("Recommend to follow the instructions in https://www.ventoy.net to use Ventoy.\n");
1389 grub_printf("\n\nWill continue to boot after 10 seconds ...... ");
1397 int ventoy_check_device(grub_device_t dev
)
1400 grub_uint64_t offset
;
1405 struct grub_partition
*partition
;
1407 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
1409 return ventoy_check_device_result(1);
1412 partition
= dev
->disk
->partition
;
1413 if (partition
->number
!= 0 || partition
->start
!= 2048)
1415 return ventoy_check_device_result(2);
1418 offset
= partition
->start
+ partition
->len
;
1420 /* We must have partition 2 */
1421 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
1424 return ventoy_check_device_result(3);
1427 partition
= file
->device
->disk
->partition
;
1428 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
1430 grub_file_close(file
);
1431 return ventoy_check_device_result(4);
1433 grub_file_close(file
);
1435 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
1436 dev2
= grub_device_open(devname
);
1439 return ventoy_check_device_result(5);
1442 fs
= grub_fs_probe(dev2
);
1445 grub_device_close(dev2
);
1446 return ventoy_check_device_result(6);
1449 fs
->fs_label(dev2
, &label
);
1450 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
1452 grub_device_close(dev2
);
1453 return ventoy_check_device_result(7);
1456 grub_device_close(dev2
);
1457 return ventoy_check_device_result(0);
1460 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1464 grub_device_t dev
= NULL
;
1465 img_info
*cur
= NULL
;
1466 img_info
*tail
= NULL
;
1467 img_info
*default_node
= NULL
;
1468 const char *strdata
= NULL
;
1469 char *device_name
= NULL
;
1470 const char *default_image
= NULL
;
1473 img_iterator_node
*node
= NULL
;
1474 img_iterator_node
*tmp
= NULL
;
1480 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1483 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1485 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1488 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1489 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1491 g_filt_dot_underscore_file
= 1;
1494 device_name
= grub_file_get_device_name(args
[0]);
1500 g_enum_dev
= dev
= grub_device_open(device_name
);
1506 /* make sure that we are running in a correct Ventoy device */
1507 ventoy_check_device(dev
);
1509 g_enum_fs
= fs
= grub_fs_probe(dev
);
1515 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1517 debug("unsupported fs:<%s>\n", fs
->name
);
1518 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1522 ventoy_set_env("vtoy_iso_fs", fs
->name
);
1524 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1525 if (strdata
&& strdata
[0] == '1')
1527 g_default_menu_mode
= 1;
1530 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1532 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1534 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1535 if (strdata
&& strdata
[0] == '/')
1537 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1538 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1540 g_img_iterator_head
.dir
[len
++] = '/';
1542 g_img_iterator_head
.dirlen
= len
;
1546 g_img_iterator_head
.dirlen
= 1;
1547 grub_strcpy(g_img_iterator_head
.dir
, "/");
1550 g_img_iterator_head
.tail
= &tail
;
1552 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1554 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1557 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1559 ventoy_dynamic_tree_menu(node
);
1563 node
= g_img_iterator_head
.next
;
1571 /* sort image list by image name */
1572 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1574 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1576 if (ventoy_cmp_img(cur
, tail
) > 0)
1578 ventoy_swap_img(cur
, tail
);
1583 if (g_default_menu_mode
== 1)
1585 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1586 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1587 " echo 'return ...' \n"
1591 if (g_default_menu_mode
== 0)
1593 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1596 img_len
= grub_strlen(default_image
);
1600 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1602 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1603 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1606 cur
->unsupport
? "[***********] " : "",
1607 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1609 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1611 if (g_default_menu_mode
== 0 && default_image
&& default_node
== NULL
)
1613 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1622 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1625 g_list_script_buf
[g_list_script_pos
] = 0;
1627 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1628 grub_env_set(args
[1], buf
);
1632 check_free(device_name
, grub_free
);
1633 check_free(dev
, grub_device_close
);
1635 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1639 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1641 img_info
*next
= NULL
;
1642 img_info
*cur
= g_ventoy_img_list
;
1655 g_ventoy_img_list
= NULL
;
1656 g_ventoy_img_count
= 0;
1658 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1661 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1664 img_info
*cur
= g_ventoy_img_list
;
1668 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1670 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1673 img_id
= grub_strtol(args
[0], NULL
, 10);
1674 if (img_id
>= g_ventoy_img_count
)
1676 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1679 debug("Find image %ld name \n", img_id
);
1681 while (cur
&& img_id
> 0)
1689 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
1692 debug("image name is %s\n", cur
->name
);
1694 grub_env_set(args
[1], cur
->name
);
1696 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1699 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1704 const char *id
= NULL
;
1705 img_info
*cur
= g_ventoy_img_list
;
1709 if (argc
< 1 || argc
> 2)
1711 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
1714 id
= grub_env_get("chosen");
1716 pos
= grub_strstr(id
, "VID_");
1719 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
1723 img_id
= (int)grub_strtoul(id
, NULL
, 10);
1728 if (img_id
== cur
->id
)
1737 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
1740 grub_env_set(args
[0], cur
->path
);
1744 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
1745 grub_env_set(args
[1], value
);
1748 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1751 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
)
1758 device_name
= grub_file_get_device_name(filename
);
1770 pos2
= grub_strstr(pos
, ",");
1773 pos2
= grub_strstr(pos
, ")");
1781 disk
= grub_disk_open(pos
);
1784 grub_disk_read(disk
, 0, 0x180, 16, guid
);
1785 grub_disk_close(disk
);
1792 grub_free(device_name
);
1796 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
1798 eltorito_descriptor desc
;
1800 grub_memset(&desc
, 0, sizeof(desc
));
1801 grub_file_seek(file
, 17 * 2048);
1802 grub_file_read(file
, &desc
, sizeof(desc
));
1804 if (desc
.type
!= 0 || desc
.version
!= 1)
1809 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
1810 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
1818 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
1822 grub_uint8_t buf
[512];
1824 grub_file_seek(file
, sector
* 2048);
1825 grub_file_read(file
, buf
, sizeof(buf
));
1827 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
1829 debug("%s efi eltorito in Validation Entry\n", file
->name
);
1833 if (buf
[0] == 0x01 && buf
[1] == 0x00)
1838 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
1840 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
1842 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1846 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
1848 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1853 debug("%s does not contain efi eltorito\n", file
->name
);
1857 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
1860 const char *fs
= NULL
;
1861 const char *cdprompt
= NULL
;
1863 grub_uint8_t chksum
= 0;
1866 disk
= file
->device
->disk
;
1867 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
1869 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
1870 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
1871 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
1873 pos
= grub_strstr(file
->name
, "/");
1879 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
1881 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
);
1883 param
->vtoy_img_size
= file
->size
;
1885 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
1886 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
1888 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
1890 /* Windows CD/DVD prompt 0:suppress 1:reserved */
1891 param
->vtoy_reserved
[4] = 0;
1892 if (g_ventoy_chain_type
== 1) /* Windows */
1894 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1895 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
1897 param
->vtoy_reserved
[4] = 1;
1901 fs
= ventoy_get_env("ventoy_fs_probe");
1902 if (fs
&& grub_strcmp(fs
, "udf") == 0)
1904 param
->vtoy_reserved
[3] = 1;
1907 /* calculate checksum */
1908 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1910 chksum
+= *((grub_uint8_t
*)param
+ i
);
1912 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
1917 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1919 grub_uint32_t i
= 0;
1920 grub_uint64_t total
= 0;
1921 ventoy_img_chunk
*chunk
= NULL
;
1923 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1925 chunk
= chunklist
->chunk
+ i
;
1927 if (chunk
->disk_start_sector
<= start
)
1929 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
1933 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
1936 if (total
!= ((file
->size
+ 511) / 512))
1938 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
1945 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1949 grub_uint32_t i
= 0;
1950 grub_uint32_t sector
= 0;
1951 grub_uint32_t count
= 0;
1952 grub_off_t size
= 0;
1953 grub_off_t read
= 0;
1955 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
1956 if (fs_type
== ventoy_fs_exfat
)
1958 grub_fat_get_file_chunk(start
, file
, chunklist
);
1960 else if (fs_type
== ventoy_fs_ext
)
1962 grub_ext_get_file_chunk(start
, file
, chunklist
);
1966 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
1967 file
->read_hook_data
= chunklist
;
1969 for (size
= file
->size
; size
> 0; size
-= read
)
1971 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
1972 grub_file_read(file
, NULL
, read
);
1975 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
1977 chunklist
->chunk
[i
].disk_start_sector
+= start
;
1978 chunklist
->chunk
[i
].disk_end_sector
+= start
;
1981 if (ventoy_fs_udf
== fs_type
)
1983 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1985 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
1986 chunklist
->chunk
[i
].img_start_sector
= sector
;
1987 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
1993 len
= (int)grub_strlen(file
->name
);
1994 if (grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0)
1996 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1998 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2008 chunklist
->chunk
[i
].img_start_sector
= sector
;
2009 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2017 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2021 grub_disk_addr_t start
;
2026 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2029 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2032 if (g_img_chunk_list
.chunk
)
2034 grub_free(g_img_chunk_list
.chunk
);
2037 /* get image chunk data */
2038 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2039 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2040 if (NULL
== g_img_chunk_list
.chunk
)
2042 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2045 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2046 g_img_chunk_list
.cur_chunk
= 0;
2048 start
= file
->device
->disk
->partition
->start
;
2050 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2052 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2053 grub_file_close(file
);
2057 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2060 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2061 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2064 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2069 char configfile
[128];
2070 install_template
*node
= NULL
;
2076 debug("select auto installation argc:%d\n", argc
);
2083 node
= ventoy_plugin_find_install_template(args
[0]);
2086 debug("Auto install template not found for %s\n", args
[0]);
2090 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2092 node
->cursel
= node
->autosel
- 1;
2093 debug("Auto install template auto select %d\n", node
->autosel
);
2097 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2103 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
2104 " echo %s\n}\n", "123");
2106 for (i
= 0; i
< node
->templatenum
; i
++)
2108 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2110 node
->templatepath
[i
].path
);
2113 g_ventoy_menu_esc
= 1;
2114 g_ventoy_suppress_esc
= 1;
2116 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2117 grub_script_execute_sourcecode(configfile
);
2119 g_ventoy_menu_esc
= 0;
2120 g_ventoy_suppress_esc
= 0;
2124 node
->cursel
= g_ventoy_last_entry
- 1;
2126 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2129 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2134 char configfile
[128];
2135 persistence_config
*node
;
2141 debug("select persistence argc:%d\n", argc
);
2148 node
= ventoy_plugin_find_persistent(args
[0]);
2151 debug("Persistence image not found for %s\n", args
[0]);
2155 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
2157 node
->cursel
= node
->autosel
- 1;
2158 debug("Persistence image auto select %d\n", node
->autosel
);
2162 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2168 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
2169 " echo %s\n}\n", "123");
2171 for (i
= 0; i
< node
->backendnum
; i
++)
2173 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
2175 node
->backendpath
[i
].path
);
2179 g_ventoy_menu_esc
= 1;
2180 g_ventoy_suppress_esc
= 1;
2182 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
2183 grub_script_execute_sourcecode(configfile
);
2185 g_ventoy_menu_esc
= 0;
2186 g_ventoy_suppress_esc
= 0;
2190 node
->cursel
= g_ventoy_last_entry
- 1;
2192 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2195 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2198 ventoy_img_chunk
*cur
;
2204 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
2206 cur
= g_img_chunk_list
.chunk
+ i
;
2207 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
2208 cur
->img_start_sector
, cur
->img_end_sector
,
2209 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
2213 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2216 #ifdef GRUB_MACHINE_EFI
2217 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2225 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2228 ulong chain_len
= 0;
2229 char *chain_data
= NULL
;
2230 char *relocator_addr
= NULL
;
2231 grub_relocator_chunk_t ch
;
2232 struct grub_relocator
*relocator
= NULL
;
2233 char envbuf
[64] = { 0 };
2244 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
2245 chain_len
= grub_strtoul(args
[1], NULL
, 10);
2247 relocator
= grub_relocator_new ();
2250 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
2254 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
2255 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
2259 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
2260 grub_relocator_unload (relocator
);
2264 relocator_addr
= get_virtual_current_address(ch
);
2266 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
2268 grub_relocator_unload (relocator
);
2270 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
2271 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
2273 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2277 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2281 ventoy_img_chunk_list chunklist
;
2286 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2289 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2292 /* get image chunk data */
2293 grub_memset(&chunklist
, 0, sizeof(chunklist
));
2294 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2295 if (NULL
== chunklist
.chunk
)
2297 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2300 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
2301 chunklist
.cur_chunk
= 0;
2303 ventoy_get_block_list(file
, &chunklist
, 0);
2305 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
2307 grub_printf("########## UNSUPPORTED ###############\n");
2310 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
2312 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2314 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2315 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
2318 grub_printf("\n==================================\n");
2320 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
2322 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
2323 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
2324 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
2325 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
2326 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
2330 grub_free(chunklist
.chunk
);
2331 grub_file_close(file
);
2333 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2336 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2339 ventoy_grub_param_file_replace
*replace
= NULL
;
2347 replace
= &(g_grub_param
->file_replace
);
2348 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
2350 replace
->old_name_cnt
= 0;
2351 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
2353 replace
->old_name_cnt
++;
2354 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
2357 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
2360 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2363 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2371 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2372 grub_printf("%s", g_list_script_buf
);
2376 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2377 grub_printf("%s", g_tree_script_buf
);
2383 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2385 img_info
*cur
= g_ventoy_img_list
;
2393 grub_printf("path:<%s> id=%d\n", cur
->path
, cur
->id
);
2394 grub_printf("name:<%s>\n\n", cur
->name
);
2401 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2407 ventoy_plugin_dump_injection();
2412 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2418 ventoy_plugin_dump_auto_install();
2423 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2429 ventoy_plugin_dump_persistence();
2434 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2445 if (args
[0][0] == '0')
2447 return g_ventoy_memdisk_mode
? 0 : 1;
2449 else if (args
[0][0] == '1')
2451 return g_ventoy_iso_raw
? 0 : 1;
2453 else if (args
[0][0] == '2')
2455 return g_ventoy_iso_uefi_drv
? 0 : 1;
2461 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2463 static int configfile_mode
= 0;
2464 char memfile
[128] = {0};
2471 * args[0]: 0:normal 1:configfile
2472 * args[1]: 0:list_buf 1:tree_buf
2477 debug("Invalid argc %d\n", argc
);
2481 if (args
[0][0] == '0')
2483 if (args
[1][0] == '0')
2485 grub_script_execute_sourcecode(g_list_script_buf
);
2489 grub_script_execute_sourcecode(g_tree_script_buf
);
2494 if (configfile_mode
)
2496 debug("Now already in F3 mode %d\n", configfile_mode
);
2500 if (args
[1][0] == '0')
2502 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2503 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2507 g_ventoy_last_entry
= -1;
2508 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2509 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2512 configfile_mode
= 1;
2513 grub_script_execute_sourcecode(memfile
);
2514 configfile_mode
= 0;
2520 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2531 g_ventoy_case_insensitive
= 1;
2532 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2533 g_ventoy_case_insensitive
= 0;
2539 grub_file_close(file
);
2545 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2550 const char *isopath
= NULL
;
2552 ventoy_mbr_head mbr
;
2559 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2562 isopath
= grub_env_get("vtoy_iso_part");
2565 debug("isopath is null %p\n", isopath
);
2569 debug("isopath is %s\n", isopath
);
2571 for (id
= 0; id
< 30 && (find
== 0); id
++)
2573 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2574 if (grub_strstr(isopath
, hdname
))
2576 debug("skip %s ...\n", hdname
);
2580 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2582 disk
= grub_disk_open(hdname
);
2585 debug("%s not exist\n", hdname
);
2589 grub_memset(&mbr
, 0, sizeof(mbr
));
2590 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2592 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2594 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2595 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2598 grub_env_set(args
[0], hdname
);
2602 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
2606 debug("read %s failed\n", hdname
);
2609 grub_disk_close(disk
);
2615 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2626 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
2629 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2632 debug("failed to open file %s\n", args
[0]);
2636 buf
= grub_malloc(len
);
2643 grub_file_read(file
, buf
, len
- 1);
2645 ventoy_get_line(buf
);
2646 ventoy_set_env(args
[1], buf
);
2650 grub_check_free(buf
);
2651 grub_file_close(file
);
2656 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
2661 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
2662 "0 %llu linear /dev/ventoy %llu\n",
2663 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
2668 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2670 char *device_name
= NULL
;
2671 grub_device_t dev
= NULL
;
2676 g_part_list_pos
= 0;
2677 grub_env_unset("vtoy_img_part_file");
2684 device_name
= grub_file_get_device_name(args
[0]);
2687 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
2691 dev
= grub_device_open(device_name
);
2694 debug("grub_device_open failed, %s\n", device_name
);
2698 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, NULL
);
2700 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
2701 grub_env_set("vtoy_img_part_file", buf
);
2705 check_free(device_name
, grub_free
);
2706 check_free(dev
, grub_device_close
);
2712 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2723 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
2726 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2729 debug("failed to open file %s\n", args
[0]);
2733 buf
= grub_malloc(file
->size
+ 1);
2739 buf
[file
->size
] = 0;
2740 grub_file_read(file
, buf
, file
->size
);
2742 if (grub_strstr(buf
, args
[1]))
2749 grub_check_free(buf
);
2750 grub_file_close(file
);
2755 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2760 ventoy_iso9660_vd pvd
;
2767 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
2770 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2773 debug("failed to open file %s\n", args
[0]);
2777 grub_file_seek(file
, 16 * 2048);
2778 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
2779 if (len
!= sizeof(pvd
))
2781 debug("failed to read pvd %d\n", len
);
2785 grub_memset(buf
, 0, sizeof(buf
));
2786 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
2787 ventoy_set_env(args
[1], buf
);
2789 grub_memset(buf
, 0, sizeof(buf
));
2790 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
2791 ventoy_set_env(args
[2], buf
);
2794 grub_file_close(file
);
2799 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2810 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
2813 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2816 debug("failed to open file %s\n", args
[0]);
2820 grub_memset(buf
, 0, sizeof(buf
));
2821 grub_file_seek(file
, 16 * 2048 + 813);
2822 len
= (int)grub_file_read(file
, buf
, 17);
2825 debug("failed to read create date %d\n", len
);
2829 ventoy_set_env(args
[1], buf
);
2832 grub_file_close(file
);
2837 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2843 ventoy_env_hook_root(1);
2848 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2854 ventoy_env_hook_root(0);
2859 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2865 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
2866 g_ventoy_last_entry
= -1;
2871 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2877 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
2882 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
2884 const char *pos
= filename
+ 1;
2892 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
2894 grub_strncpy((char *)data
, filename
, 128);
2905 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2908 char *device_name
= NULL
;
2909 grub_device_t dev
= NULL
;
2910 grub_fs_t fs
= NULL
;
2911 char buf
[128] = {0};
2917 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
2921 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
2923 device_name
= grub_file_get_device_name(args
[0]);
2926 debug("grub_file_get_device_name failed, %s\n", args
[0]);
2930 dev
= grub_device_open(device_name
);
2933 debug("grub_device_open failed, %s\n", device_name
);
2937 fs
= grub_fs_probe(dev
);
2940 debug("grub_fs_probe failed, %s\n", device_name
);
2944 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
2948 ventoy_set_env(args
[2], buf
);
2955 check_free(device_name
, grub_free
);
2956 check_free(dev
, grub_device_close
);
2961 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2964 char *device_name
= NULL
;
2965 grub_device_t dev
= NULL
;
2966 grub_fs_t fs
= NULL
;
2973 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
2977 device_name
= grub_file_get_device_name(args
[0]);
2980 debug("grub_file_get_device_name failed, %s\n", args
[0]);
2984 dev
= grub_device_open(device_name
);
2987 debug("grub_device_open failed, %s\n", device_name
);
2991 fs
= grub_fs_probe(dev
);
2994 debug("grub_fs_probe failed, %s\n", device_name
);
2998 fs
->fs_label(dev
, &label
);
3001 ventoy_set_env(args
[1], label
);
3009 check_free(device_name
, grub_free
);
3010 check_free(dev
, grub_device_close
);
3015 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
3019 grub_snprintf((char *)data
, 256, "%s", filename
);
3027 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3030 char *device_name
= NULL
;
3031 grub_device_t dev
= NULL
;
3032 grub_fs_t fs
= NULL
;
3033 char name
[256] ={0};
3039 debug("ventoy_cmd_fs_enum_1st_file, invalid param num %d\n", argc
);
3043 device_name
= grub_file_get_device_name(args
[0]);
3046 debug("grub_file_get_device_name failed, %s\n", args
[0]);
3050 dev
= grub_device_open(device_name
);
3053 debug("grub_device_open failed, %s\n", device_name
);
3057 fs
= grub_fs_probe(dev
);
3060 debug("grub_fs_probe failed, %s\n", device_name
);
3064 fs
->fs_dir(dev
, args
[1], ventoy_fs_enum_1st_file
, name
);
3067 ventoy_set_env(args
[2], name
);
3074 check_free(device_name
, grub_free
);
3075 check_free(dev
, grub_device_close
);
3080 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3090 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
3094 for (pos
= args
[0]; *pos
; pos
++)
3108 grub_env_set(args
[1], args
[0]);
3118 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
3120 grub_uint64_t size
= 0;
3123 char fullpath
[256] = {0};
3126 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3129 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
3132 debug("grub_file_open failed <%s>\n", fullpath
);
3138 grub_file_close(file
);
3142 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
3146 char fullpath
[256] = {0};
3149 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
3152 file
= grub_file_open(fullpath
, type
);
3155 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
3162 int ventoy_is_file_exist(const char *fmt
, ...)
3167 char buf
[256] = {0};
3169 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
3173 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3176 grub_strncpy(pos
+ len
, " ]", 2);
3178 debug("script exec %s\n", buf
);
3180 if (0 == grub_script_execute_sourcecode(buf
))
3188 int ventoy_is_dir_exist(const char *fmt
, ...)
3193 char buf
[256] = {0};
3195 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
3199 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
3202 grub_strncpy(pos
+ len
, " ]", 2);
3204 debug("script exec %s\n", buf
);
3206 if (0 == grub_script_execute_sourcecode(buf
))
3214 static int ventoy_env_init(void)
3218 grub_env_set("vtdebug_flag", "");
3220 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
3221 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3222 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3224 ventoy_filt_register(0, ventoy_wrapper_open
);
3226 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
3229 g_grub_param
->grub_env_get
= grub_env_get
;
3230 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
3231 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
3232 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
3233 grub_env_set("env_param", buf
);
3239 static cmd_para ventoy_cmds
[] =
3241 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
3242 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
3243 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
3244 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3245 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
3246 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
3247 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
3248 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
3249 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
3250 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
3251 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
3252 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
3253 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
3254 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
3255 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
3256 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
3257 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
3258 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
3260 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
3261 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
3262 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
3263 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
3264 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
3265 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
3267 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
3268 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
3269 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
3273 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
3274 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
3275 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
3276 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
3277 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
3278 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
3279 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
3280 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
3281 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
3282 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
3284 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
3285 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
3286 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
3287 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
3288 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
3289 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
3291 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3292 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
3293 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
3294 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
3295 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
3296 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
3297 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
3298 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
3299 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
3300 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
3302 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
3303 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
3304 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
3305 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
3306 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
3307 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
3308 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
3310 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
3311 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
3312 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
3313 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
3316 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
3317 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
3319 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
3320 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
3321 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
3324 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
3325 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
3326 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
3327 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
3328 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
3329 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
3330 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
3331 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
3333 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
3334 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
3340 GRUB_MOD_INIT(ventoy
)
3343 cmd_para
*cur
= NULL
;
3347 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
3349 cur
= ventoy_cmds
+ i
;
3350 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
3351 cur
->summary
, cur
->description
, cur
->parser
);
3355 GRUB_MOD_FINI(ventoy
)
3359 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
3361 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);