1 /******************************************************************************
4 * Copyright (c) 2021, 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/api.h>
40 #include <grub/efi/efi.h>
42 #include <grub/time.h>
43 #include <grub/video.h>
44 #include <grub/acpi.h>
45 #include <grub/charset.h>
46 #include <grub/crypto.h>
47 #include <grub/lib/crc.h>
48 #include <grub/ventoy.h>
49 #include "ventoy_def.h"
52 GRUB_MOD_LICENSE ("GPLv3+");
54 initrd_info
*g_initrd_img_list
= NULL
;
55 initrd_info
*g_initrd_img_tail
= NULL
;
56 int g_initrd_img_count
= 0;
57 int g_valid_initrd_count
= 0;
58 int g_default_menu_mode
= 0;
59 int g_filt_dot_underscore_file
= 0;
60 int g_sort_case_sensitive
= 0;
61 int g_tree_view_menu_style
= 0;
62 static grub_file_t g_old_file
;
63 static int g_ventoy_last_entry_back
;
66 char g_img_swap_tmp_buf
[1024];
67 img_info g_img_swap_tmp
;
68 img_info
*g_ventoy_img_list
= NULL
;
70 int g_ventoy_img_count
= 0;
72 grub_device_t g_enum_dev
= NULL
;
73 grub_fs_t g_enum_fs
= NULL
;
74 int g_img_max_search_level
= -1;
75 img_iterator_node g_img_iterator_head
;
76 img_iterator_node
*g_img_iterator_tail
= NULL
;
78 grub_uint8_t g_ventoy_break_level
= 0;
79 grub_uint8_t g_ventoy_debug_level
= 0;
80 grub_uint8_t g_ventoy_chain_type
= 0;
82 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
83 grub_uint32_t g_ventoy_cpio_size
= 0;
84 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
85 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
87 int g_plugin_image_list
= 0;
89 ventoy_grub_param
*g_grub_param
= NULL
;
91 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
93 ventoy_img_chunk_list g_img_chunk_list
;
95 int g_wimboot_enable
= 0;
96 ventoy_img_chunk_list g_wimiso_chunk_list
;
97 char *g_wimiso_path
= NULL
;
99 int g_vhdboot_enable
= 0;
101 grub_uint64_t g_conf_replace_offset
= 0;
102 grub_uint64_t g_svd_replace_offset
= 0;
103 conf_replace
*g_conf_replace_node
= NULL
;
104 grub_uint8_t
*g_conf_replace_new_buf
= NULL
;
105 int g_conf_replace_new_len
= 0;
106 int g_conf_replace_new_len_align
= 0;
108 ventoy_gpt_info
*g_ventoy_part_info
= NULL
;
109 grub_uint64_t g_ventoy_disk_size
= 0;
110 grub_uint64_t g_ventoy_disk_part_size
[2];
112 static char *g_tree_script_buf
= NULL
;
113 static int g_tree_script_pos
= 0;
115 static char *g_list_script_buf
= NULL
;
116 static int g_list_script_pos
= 0;
118 static char *g_part_list_buf
= NULL
;
119 static int g_part_list_pos
= 0;
121 static int g_video_mode_max
= 0;
122 static int g_video_mode_num
= 0;
123 static ventoy_video_mode
*g_video_mode_list
= NULL
;
125 static int g_enumerate_time_checked
= 0;
126 static grub_uint64_t g_enumerate_start_time_ms
;
127 static grub_uint64_t g_enumerate_finish_time_ms
;
128 static int g_vtoy_file_flt
[VTOY_FILE_FLT_BUTT
] = {0};
130 static int g_pager_flag
= 0;
131 static char g_old_pager
[32];
133 static const char *g_vtoy_winpeshl_ini
= "[LaunchApps]\r\nvtoyjump.exe";
135 static const char *g_menu_class
[] =
137 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy"
140 const char *g_menu_prefix
[img_type_max
] =
142 "iso", "wim", "efi", "img", "vhd", "vtoy"
145 static int g_vtoy_load_prompt
= 0;
146 static char g_vtoy_prompt_msg
[64];
148 static char g_json_case_mis_path
[32];
150 static int ventoy_get_fs_type(const char *fs
)
154 return ventoy_fs_max
;
156 else if (grub_strncmp(fs
, "exfat", 5) == 0)
158 return ventoy_fs_exfat
;
160 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
162 return ventoy_fs_ntfs
;
164 else if (grub_strncmp(fs
, "ext", 3) == 0)
166 return ventoy_fs_ext
;
168 else if (grub_strncmp(fs
, "xfs", 3) == 0)
170 return ventoy_fs_xfs
;
172 else if (grub_strncmp(fs
, "udf", 3) == 0)
174 return ventoy_fs_udf
;
176 else if (grub_strncmp(fs
, "fat", 3) == 0)
178 return ventoy_fs_fat
;
181 return ventoy_fs_max
;
184 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
203 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
205 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
209 static int ventoy_control_get_flag(const char *key
)
211 const char *val
= ventoy_get_env(key
);
213 if (val
&& val
[0] == '1' && val
[1] == 0)
220 static grub_err_t
ventoy_fs_close(grub_file_t file
)
222 grub_file_close(g_old_file
);
223 grub_free(file
->data
);
231 static int ventoy_video_hook(const struct grub_video_mode_info
*info
, void *hook_arg
)
237 if (info
->mode_type
& GRUB_VIDEO_MODE_TYPE_PURE_TEXT
)
242 for (i
= 0; i
< g_video_mode_num
; i
++)
244 if (g_video_mode_list
[i
].width
== info
->width
&&
245 g_video_mode_list
[i
].height
== info
->height
&&
246 g_video_mode_list
[i
].bpp
== info
->bpp
)
252 g_video_mode_list
[g_video_mode_num
].width
= info
->width
;
253 g_video_mode_list
[g_video_mode_num
].height
= info
->height
;
254 g_video_mode_list
[g_video_mode_num
].bpp
= info
->bpp
;
257 if (g_video_mode_num
== g_video_mode_max
)
259 g_video_mode_max
*= 2;
260 g_video_mode_list
= grub_realloc(g_video_mode_list
, g_video_mode_max
* sizeof(ventoy_video_mode
));
266 static int ventoy_video_mode_cmp(ventoy_video_mode
*v1
, ventoy_video_mode
*v2
)
268 if (v1
->bpp
== v2
->bpp
)
270 if (v1
->width
== v2
->width
)
272 if (v1
->height
== v2
->height
)
278 return (v1
->height
< v2
->height
) ? -1 : 1;
283 return (v1
->width
< v2
->width
) ? -1 : 1;
288 return (v1
->bpp
< v2
->bpp
) ? -1 : 1;
292 static int ventoy_enum_video_mode(void)
295 grub_video_adapter_t adapter
;
296 grub_video_driver_id_t id
;
297 ventoy_video_mode mode
;
299 g_video_mode_num
= 0;
300 g_video_mode_max
= 1024;
301 g_video_mode_list
= grub_malloc(sizeof(ventoy_video_mode
) * g_video_mode_max
);
302 if (!g_video_mode_list
)
307 #ifdef GRUB_MACHINE_PCBIOS
308 grub_dl_load ("vbe");
311 id
= grub_video_get_driver_id ();
313 FOR_VIDEO_ADAPTERS (adapter
)
315 if (!adapter
->iterate
||
316 (adapter
->id
!= id
&& (id
!= GRUB_VIDEO_DRIVER_NONE
||
317 adapter
->init() != GRUB_ERR_NONE
)))
322 adapter
->iterate(ventoy_video_hook
, NULL
);
324 if (adapter
->id
!= id
)
330 /* sort video mode */
331 for (i
= 0; i
< g_video_mode_num
; i
++)
332 for (j
= i
+ 1; j
< g_video_mode_num
; j
++)
334 if (ventoy_video_mode_cmp(g_video_mode_list
+ i
, g_video_mode_list
+ j
) < 0)
336 grub_memcpy(&mode
, g_video_mode_list
+ i
, sizeof(ventoy_video_mode
));
337 grub_memcpy(g_video_mode_list
+ i
, g_video_mode_list
+ j
, sizeof(ventoy_video_mode
));
338 grub_memcpy(g_video_mode_list
+ j
, &mode
, sizeof(ventoy_video_mode
));
342 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
345 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
349 static struct grub_fs vtoy_fs
=
354 .fs_read
= ventoy_fs_read
,
355 .fs_close
= ventoy_fs_close
,
365 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
371 file
->data
= grub_malloc(rawFile
->size
+ 4096);
377 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
378 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
380 g_old_file
= rawFile
;
382 file
->size
= rawFile
->size
+ len
;
383 file
->device
= rawFile
->device
;
385 file
->not_easily_seekable
= 1;
390 static int ventoy_check_decimal_var(const char *name
, long *value
)
392 const char *value_str
= NULL
;
394 value_str
= grub_env_get(name
);
395 if (NULL
== value_str
)
397 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
400 if (!ventoy_is_decimal(value_str
))
402 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
405 *value
= grub_strtol(value_str
, NULL
, 10);
407 return GRUB_ERR_NONE
;
410 grub_uint64_t
ventoy_get_vtoy_partsize(int part
)
412 grub_uint64_t sectors
;
414 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
416 sectors
= g_ventoy_part_info
->PartTbl
[part
].LastLBA
+ 1 - g_ventoy_part_info
->PartTbl
[part
].StartLBA
;
420 sectors
= g_ventoy_part_info
->MBR
.PartTbl
[part
].SectorCount
;
423 return sectors
* 512;
426 static int ventoy_load_efiboot_template(char **buf
, int *datalen
, int *direntoff
)
432 grub_uint32_t offset
;
434 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
437 debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
441 len
= (int)file
->size
;
443 data
= (char *)grub_malloc(file
->size
);
449 grub_file_read(file
, data
, file
->size
);
450 grub_file_close(file
);
452 grub_snprintf(exec
, sizeof(exec
), "loopback efiboot mem:0x%llx:size:%d", (ulonglong
)(ulong
)data
, len
);
453 grub_script_execute_sourcecode(exec
);
455 file
= grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD
);
456 offset
= (grub_uint32_t
)grub_iso9660_get_last_file_dirent_pos(file
);
457 grub_file_close(file
);
459 grub_script_execute_sourcecode("loopback -d efiboot");
463 *direntoff
= offset
+ 2;
468 static int ventoy_set_check_result(int ret
)
472 grub_snprintf(buf
, sizeof(buf
), "%d", (ret
& 0x7FFF));
473 grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf
);
474 grub_env_export("VTOY_CHKDEV_RESULT_STRING");
478 grub_printf(VTOY_WARNING
"\n");
479 grub_printf(VTOY_WARNING
"\n");
480 grub_printf(VTOY_WARNING
"\n\n\n");
482 grub_printf("This is NOT a standard Ventoy device and is NOT supported (0x%x).\n\n", ret
);
483 grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n");
485 grub_printf("\n\nWill exit after 10 seconds ...... ");
493 static int ventoy_check_official_device(grub_device_t dev
)
497 grub_uint64_t offset
;
502 struct grub_partition
*partition
;
504 if (dev
->disk
== NULL
|| dev
->disk
->partition
== NULL
)
506 return ventoy_set_check_result(1 | 0x1000);
509 if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
510 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev
->disk
->name
) ||
511 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
513 #ifndef GRUB_MACHINE_EFI
514 if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev
->disk
->name
) ||
515 0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev
->disk
->name
) ||
516 0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev
->disk
->name
))
518 return ventoy_set_check_result(2 | 0x1000);
527 /* We must have partition 2 */
530 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", "(ventoydisk)/ventoy/ventoy.cpio");
534 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(%s,2)/ventoy/ventoy.cpio", dev
->disk
->name
);
538 return ventoy_set_check_result(3 | 0x1000);
541 if (NULL
== grub_strstr(file
->fs
->name
, "fat"))
543 grub_file_close(file
);
544 return ventoy_set_check_result(4 | 0x1000);
547 partition
= dev
->disk
->partition
;
548 if (partition
->number
!= 0 || partition
->start
!= 2048)
550 return ventoy_set_check_result(5);
555 if (grub_strncmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
557 ventoy_gpt_part_tbl
*PartTbl
= g_ventoy_part_info
->PartTbl
;
558 if (PartTbl
[1].StartLBA
!= PartTbl
[0].LastLBA
+ 1 ||
559 (PartTbl
[1].LastLBA
+ 1 - PartTbl
[1].StartLBA
) != 65536)
561 grub_file_close(file
);
562 return ventoy_set_check_result(6);
567 ventoy_part_table
*PartTbl
= g_ventoy_part_info
->MBR
.PartTbl
;
568 if (PartTbl
[1].StartSectorId
!= PartTbl
[0].StartSectorId
+ PartTbl
[0].SectorCount
||
569 PartTbl
[1].SectorCount
!= 65536)
571 grub_file_close(file
);
572 return ventoy_set_check_result(6);
578 offset
= partition
->start
+ partition
->len
;
579 partition
= file
->device
->disk
->partition
;
580 if ((partition
->number
!= 1) || (partition
->len
!= 65536) || (offset
!= partition
->start
))
582 grub_file_close(file
);
583 return ventoy_set_check_result(7);
587 grub_file_close(file
);
591 grub_snprintf(devname
, sizeof(devname
), "%s,2", dev
->disk
->name
);
592 dev2
= grub_device_open(devname
);
595 return ventoy_set_check_result(8);
598 fs
= grub_fs_probe(dev2
);
601 grub_device_close(dev2
);
602 return ventoy_set_check_result(9);
605 fs
->fs_label(dev2
, &label
);
606 if ((!label
) || grub_strncmp("VTOYEFI", label
, 7))
608 grub_device_close(dev2
);
609 return ventoy_set_check_result(10);
612 grub_device_close(dev2
);
615 return ventoy_set_check_result(0);
618 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
622 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
632 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
634 grub_uint64_t size
= 0;
637 char fullpath
[256] = {0};
640 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
643 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
646 debug("grub_file_open failed <%s>\n", fullpath
);
652 grub_file_close(file
);
656 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
660 char fullpath
[256] = {0};
663 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
666 file
= grub_file_open(fullpath
, type
);
669 debug("grub_file_open failed <%s> %d\n", fullpath
, grub_errno
);
676 int ventoy_is_file_exist(const char *fmt
, ...)
683 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f \"");
687 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
690 grub_strncpy(pos
+ len
, "\" ]", 3);
692 debug("script exec %s\n", buf
);
694 if (0 == grub_script_execute_sourcecode(buf
))
702 int ventoy_is_dir_exist(const char *fmt
, ...)
709 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d \"");
713 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
716 grub_strncpy(pos
+ len
, "\" ]", 3);
718 debug("script exec %s\n", buf
);
720 if (0 == grub_script_execute_sourcecode(buf
))
728 int ventoy_gzip_compress(void *mem_in
, int mem_in_len
, void *mem_out
, int mem_out_len
)
731 grub_uint8_t
*outbuf
;
732 grub_uint8_t gzHdr
[10] =
734 0x1F, 0x8B, /* magic */
742 grub_memset(&s
, 0, sizeof(mz_stream
));
744 mz_deflateInit2(&s
, 1, MZ_DEFLATED
, -MZ_DEFAULT_WINDOW_BITS
, 6, MZ_DEFAULT_STRATEGY
);
746 outbuf
= (grub_uint8_t
*)mem_out
;
748 mem_out_len
-= sizeof(gzHdr
) + 8;
749 grub_memcpy(outbuf
, gzHdr
, sizeof(gzHdr
));
750 outbuf
+= sizeof(gzHdr
);
752 s
.avail_in
= mem_in_len
;
755 s
.avail_out
= mem_out_len
;
758 mz_deflate(&s
, MZ_FINISH
);
762 outbuf
+= s
.total_out
;
763 *(grub_uint32_t
*)outbuf
= grub_getcrc32c(0, outbuf
, s
.total_out
);
764 *(grub_uint32_t
*)(outbuf
+ 4) = (grub_uint32_t
)(s
.total_out
);
766 return s
.total_out
+ sizeof(gzHdr
) + 8;
774 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
778 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
781 if (0 == grub_strcmp(args
[0], "on"))
784 grub_env_set("vtdebug_flag", "debug");
789 grub_env_set("vtdebug_flag", "");
792 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
795 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
799 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
801 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
802 grub_printf(" level:\r\n");
803 grub_printf(" 01/11: busybox / (+cat log)\r\n");
804 grub_printf(" 02/12: initrd / (+cat log)\r\n");
805 grub_printf(" 03/13: hook / (+cat log)\r\n");
807 grub_printf(" debug:\r\n");
808 grub_printf(" 0: debug is off\r\n");
809 grub_printf(" 1: debug is on\r\n");
811 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
814 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
816 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
818 g_ventoy_debug_level
= 1;
821 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
824 static grub_err_t
ventoy_cmd_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
833 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
836 static grub_err_t
ventoy_cmd_strbegin(grub_extcmd_context_t ctxt
, int argc
, char **args
)
868 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
873 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
875 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
878 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
883 value_long
+= grub_strtol(args
[1], NULL
, 10);
885 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
886 grub_env_set(args
[0], buf
);
888 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
891 static grub_err_t
ventoy_cmd_mod(grub_extcmd_context_t ctxt
, int argc
, char **args
)
893 ulonglong value1
= 0;
894 ulonglong value2
= 0;
899 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name
);
902 value1
= grub_strtoull(args
[0], NULL
, 10);
903 value2
= grub_strtoull(args
[1], NULL
, 10);
905 grub_snprintf(buf
, sizeof(buf
), "%llu", (value1
& (value2
- 1)));
906 grub_env_set(args
[2], buf
);
908 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
911 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
926 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
929 debug("failed to open file <%s> for udf check\n", args
[0]);
933 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
935 grub_env_set(args
[1], buf
);
937 grub_file_close(file
);
943 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
951 g_wimboot_enable
= 0;
952 grub_check_free(g_wimiso_path
);
953 grub_check_free(g_wimiso_chunk_list
.chunk
);
955 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
961 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
962 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
963 if (NULL
== g_wimiso_chunk_list
.chunk
)
965 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
968 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
969 g_wimiso_chunk_list
.cur_chunk
= 0;
971 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
973 g_wimboot_enable
= 1;
974 g_wimiso_path
= grub_strdup(args
[0]);
976 grub_file_close(file
);
981 static grub_err_t
ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt
, int argc
, char **args
)
991 ventoy_iso9660_override
*dirent
;
1000 totlen
= sizeof(ventoy_chain_head
);
1002 if (ventoy_load_efiboot_template(&buf
, &len
, &offset
))
1004 debug("failed to load efiboot template %d\n", len
);
1010 debug("efiboot template len:%d offset:%d\n", len
, offset
);
1012 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
1015 debug("failed to open file <%s>\n", args
[0]);
1019 totlen
+= ventoy_align_2k(file
->size
);
1021 dirent
= (ventoy_iso9660_override
*)(buf
+ offset
);
1022 dirent
->first_sector
= len
/ 2048;
1023 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
1024 dirent
->size
= (grub_uint32_t
)file
->size
;
1025 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
1027 debug("rawiso len:%d efilen:%d total:%d\n", len
, (int)file
->size
, totlen
);
1029 #ifdef GRUB_MACHINE_EFI
1030 data
= (char *)grub_efi_allocate_iso_buf(totlen
);
1032 data
= (char *)grub_malloc(totlen
);
1035 ventoy_fill_os_param(file
, (ventoy_os_param
*)data
);
1037 grub_memcpy(data
+ sizeof(ventoy_chain_head
), buf
, len
);
1038 grub_check_free(buf
);
1040 grub_file_read(file
, data
+ sizeof(ventoy_chain_head
) + len
, file
->size
);
1041 grub_file_close(file
);
1043 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
1044 grub_snprintf(value
, sizeof(value
), "0x%llx", (ulonglong
)(ulong
)data
);
1045 grub_env_set(name
, value
);
1047 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
1048 grub_snprintf(value
, sizeof(value
), "%d", (int)(totlen
));
1049 grub_env_set(name
, value
);
1054 grub_err_t
ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1060 g_vtoy_load_prompt
= 0;
1061 grub_memset(g_vtoy_prompt_msg
, 0, sizeof(g_vtoy_prompt_msg
));
1063 if (argc
== 2 && args
[0][0] == '1')
1065 g_vtoy_load_prompt
= 1;
1066 grub_snprintf(g_vtoy_prompt_msg
, sizeof(g_vtoy_prompt_msg
), "%s", args
[1]);
1069 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1072 int ventoy_need_prompt_load_file(void)
1074 return g_vtoy_load_prompt
;
1077 grub_ssize_t
ventoy_load_file_with_prompt(grub_file_t file
, void *buf
, grub_ssize_t size
)
1079 grub_uint64_t ro
= 0;
1080 grub_uint64_t div
= 0;
1081 grub_ssize_t left
= size
;
1082 char *cur
= (char *)buf
;
1084 grub_printf("\r%s 1%% ", g_vtoy_prompt_msg
);
1087 while (left
>= VTOY_SIZE_2MB
)
1089 grub_file_read(file
, cur
, VTOY_SIZE_2MB
);
1090 cur
+= VTOY_SIZE_2MB
;
1091 left
-= VTOY_SIZE_2MB
;
1093 div
= grub_divmod64((grub_uint64_t
)((size
- left
) * 100), (grub_uint64_t
)size
, &ro
);
1094 grub_printf("\r%s %d%% ", g_vtoy_prompt_msg
, (int)div
);
1100 grub_file_read(file
, cur
, left
);
1103 grub_printf("\r%s 100%% \n", g_vtoy_prompt_msg
);
1109 static grub_err_t
ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1116 enum grub_file_type type
;
1127 if (grub_strcmp(args
[0], "nodecompress") == 0)
1129 type
= VENTOY_FILE_TYPE
;
1133 type
= GRUB_FILE_TYPE_LINUX_INITRD
;
1136 file
= ventoy_grub_file_open(type
, "%s", args
[1]);
1139 debug("failed to open file <%s>\n", args
[1]);
1143 #ifdef GRUB_MACHINE_EFI
1144 buf
= (char *)grub_efi_allocate_chain_buf(file
->size
);
1146 buf
= (char *)grub_malloc(file
->size
);
1151 grub_file_close(file
);
1155 if (g_vtoy_load_prompt
)
1157 ventoy_load_file_with_prompt(file
, buf
, file
->size
);
1161 grub_file_read(file
, buf
, file
->size
);
1164 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[2]);
1165 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
1166 grub_env_set(name
, value
);
1168 grub_snprintf(name
, sizeof(name
), "%s_size", args
[2]);
1169 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
1170 grub_env_set(name
, value
);
1172 grub_file_close(file
);
1178 static grub_err_t
ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1196 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1199 debug("failed to open file <%s> for udf check\n", args
[0]);
1203 headlen
= sizeof(ventoy_chain_head
);
1205 #ifdef GRUB_MACHINE_EFI
1206 buf
= (char *)grub_efi_allocate_iso_buf(headlen
+ file
->size
);
1208 buf
= (char *)grub_malloc(headlen
+ file
->size
);
1211 ventoy_fill_os_param(file
, (ventoy_os_param
*)buf
);
1213 grub_file_read(file
, buf
+ headlen
, file
->size
);
1215 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
1216 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
1217 grub_env_set(name
, value
);
1219 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
1220 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
1221 grub_env_set(name
, value
);
1223 grub_file_close(file
);
1229 static grub_err_t
ventoy_cmd_iso9660_is_joliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1235 if (grub_iso9660_is_joliet())
1237 debug("This time has joliet process\n");
1246 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1255 if (args
[0][0] == '1')
1257 grub_iso9660_set_nojoliet(1);
1261 grub_iso9660_set_nojoliet(0);
1267 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1272 grub_uint8_t buf
[32];
1283 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1286 debug("failed to open file <%s> for udf check\n", args
[0]);
1290 for (i
= 16; i
< 32; i
++)
1292 grub_file_seek(file
, i
* 2048);
1293 grub_file_read(file
, buf
, sizeof(buf
));
1301 grub_file_seek(file
, i
* 2048);
1302 grub_file_read(file
, buf
, sizeof(buf
));
1304 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
1307 grub_file_seek(file
, i
* 2048);
1308 grub_file_read(file
, buf
, sizeof(buf
));
1310 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
1311 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
1317 grub_file_close(file
);
1319 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
1324 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1326 long value_long1
= 0;
1327 long value_long2
= 0;
1329 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
1331 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
1334 value_long1
= grub_strtol(args
[0], NULL
, 10);
1335 value_long2
= grub_strtol(args
[2], NULL
, 10);
1337 if (0 == grub_strcmp(args
[1], "eq"))
1339 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
1341 else if (0 == grub_strcmp(args
[1], "ne"))
1343 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
1345 else if (0 == grub_strcmp(args
[1], "gt"))
1347 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
1349 else if (0 == grub_strcmp(args
[1], "lt"))
1351 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
1353 else if (0 == grub_strcmp(args
[1], "ge"))
1355 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
1357 else if (0 == grub_strcmp(args
[1], "le"))
1359 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
1363 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
1369 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1372 char buf
[128] = {0};
1376 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
1379 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
1380 pos
= grub_strstr(buf
, ",");
1386 grub_env_set(args
[1], buf
);
1388 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1391 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1397 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
1403 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
1406 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
1408 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e \"%s/%s\" ]", args
[0], files
[i
]);
1409 if (0 == grub_script_execute_sourcecode(buf
))
1411 debug("file %s exist, ventoy_compatible YES\n", buf
);
1412 grub_env_set("ventoy_compatible", "YES");
1413 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1417 debug("file %s NOT exist\n", buf
);
1421 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
1422 pos
= grub_strstr(buf
, ")");
1428 disk
= grub_disk_open(buf
);
1431 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
1432 grub_disk_close(disk
);
1434 g_img_swap_tmp_buf
[703] = 0;
1435 for (i
= 318; i
< 703; i
++)
1437 if (g_img_swap_tmp_buf
[i
] == 'V' &&
1438 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
1440 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
1441 grub_env_set("ventoy_compatible", "YES");
1442 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1448 debug("failed to open disk <%s>\n", buf
);
1451 grub_env_set("ventoy_compatible", "NO");
1452 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1455 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
1461 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1463 return (img1
->plugin_list_index
- img2
->plugin_list_index
);
1466 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
1471 if (0 == g_sort_case_sensitive
)
1473 if (grub_islower(c1
))
1475 c1
= c1
- 'a' + 'A';
1478 if (grub_islower(c2
))
1480 c2
= c2
- 'a' + 'A';
1493 static int ventoy_cmp_subdir(img_iterator_node
*node1
, img_iterator_node
*node2
)
1499 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1501 return (node1
->plugin_list_index
- node2
->plugin_list_index
);
1504 for (s1
= node1
->dir
, s2
= node2
->dir
; *s1
&& *s2
; s1
++, s2
++)
1509 if (0 == g_sort_case_sensitive
)
1511 if (grub_islower(c1
))
1513 c1
= c1
- 'a' + 'A';
1516 if (grub_islower(c2
))
1518 c2
= c2
- 'a' + 'A';
1531 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
1533 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
1535 grub_memcpy(img1
, img2
, sizeof(img_info
));
1536 img1
->next
= g_img_swap_tmp
.next
;
1537 img1
->prev
= g_img_swap_tmp
.prev
;
1539 g_img_swap_tmp
.next
= img2
->next
;
1540 g_img_swap_tmp
.prev
= img2
->prev
;
1541 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
1544 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
1548 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1556 static int ventoy_collect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
1565 const menu_tip
*tip
;
1566 img_iterator_node
*tmp
;
1567 img_iterator_node
*new_node
;
1568 img_iterator_node
*node
= (img_iterator_node
*)data
;
1570 if (g_enumerate_time_checked
== 0)
1572 g_enumerate_finish_time_ms
= grub_get_time_ms();
1573 if ((g_enumerate_finish_time_ms
- g_enumerate_start_time_ms
) >= 3000)
1576 grub_printf("\n\n Ventoy scanning files, please wait...\n");
1578 g_enumerate_time_checked
= 1;
1582 len
= grub_strlen(filename
);
1586 if (node
->level
+ 1 > g_img_max_search_level
)
1591 if ((len
== 1 && filename
[0] == '.') ||
1592 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
1597 if (!ventoy_img_name_valid(filename
, len
))
1602 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
1607 if (g_plugin_image_list
== VENTOY_IMG_WHITE_LIST
)
1609 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s/", node
->dir
, filename
);
1610 index
= ventoy_plugin_get_image_list_index(vtoy_class_directory
, g_img_swap_tmp_buf
);
1613 debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1618 new_node
= grub_zalloc(sizeof(img_iterator_node
));
1621 new_node
->level
= node
->level
+ 1;
1622 new_node
->plugin_list_index
= index
;
1623 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
1625 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
1628 debug("Directory %s ignored...\n", new_node
->dir
);
1629 grub_free(new_node
);
1633 new_node
->tail
= node
->tail
;
1635 new_node
->parent
= node
;
1636 if (!node
->firstchild
)
1638 node
->firstchild
= new_node
;
1641 if (g_img_iterator_tail
)
1643 g_img_iterator_tail
->next
= new_node
;
1644 g_img_iterator_tail
= new_node
;
1648 g_img_iterator_head
.next
= new_node
;
1649 g_img_iterator_tail
= new_node
;
1655 debug("Find a file %s\n", filename
);
1661 if (FILE_FLT(ISO
) && 0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
1663 type
= img_type_iso
;
1665 else if (FILE_FLT(WIM
) && g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
1667 type
= img_type_wim
;
1669 else if (FILE_FLT(VHD
) && g_vhdboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".vhd") ||
1670 (len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vhdx"))))
1672 type
= img_type_vhd
;
1674 #ifdef GRUB_MACHINE_EFI
1675 else if (FILE_FLT(EFI
) && 0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
1677 type
= img_type_efi
;
1680 else if (FILE_FLT(IMG
) && 0 == grub_strcasecmp(filename
+ len
- 4, ".img"))
1682 if (len
== 18 && grub_strncmp(filename
, "ventoy_", 7) == 0)
1684 if (grub_strncmp(filename
+ 7, "wimboot", 7) == 0 ||
1685 grub_strncmp(filename
+ 7, "vhdboot", 7) == 0)
1690 type
= img_type_img
;
1692 else if (FILE_FLT(VTOY
) && len
>= 5 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vtoy"))
1694 type
= img_type_vtoy
;
1696 else if (len
>= 9 && 0 == grub_strcasecmp(filename
+ len
- 5, ".vcfg"))
1698 if (filename
[len
- 9] == '.' || (len
>= 10 && filename
[len
- 10] == '.'))
1700 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1701 ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf
);
1710 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
1715 if (g_plugin_image_list
)
1717 grub_snprintf(g_img_swap_tmp_buf
, sizeof(g_img_swap_tmp_buf
), "%s%s", node
->dir
, filename
);
1718 index
= ventoy_plugin_get_image_list_index(vtoy_class_image_file
, g_img_swap_tmp_buf
);
1719 if (VENTOY_IMG_WHITE_LIST
== g_plugin_image_list
&& index
== 0)
1721 debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf
);
1724 else if (VENTOY_IMG_BLACK_LIST
== g_plugin_image_list
&& index
> 0)
1726 debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf
, index
);
1731 img
= grub_zalloc(sizeof(img_info
));
1735 img
->plugin_list_index
= index
;
1736 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
1738 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
1740 img
->size
= info
->size
;
1743 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
1746 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
1748 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
1753 if (g_ventoy_img_list
)
1755 tail
= *(node
->tail
);
1761 g_ventoy_img_list
= img
;
1764 img
->id
= g_ventoy_img_count
;
1766 if (node
&& NULL
== node
->firstiso
)
1768 node
->firstiso
= img
;
1779 *((img_info
**)(node
->tail
)) = img
;
1780 g_ventoy_img_count
++;
1782 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
1784 tip
= ventoy_plugin_get_menu_tip(img
->path
);
1787 img
->tip1
= tip
->tip1
;
1788 img
->tip2
= tip
->tip2
;
1791 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
, img
->path
);
1794 img
->class = g_menu_class
[type
];
1796 img
->menu_prefix
= g_menu_prefix
[type
];
1798 if (img_type_iso
== type
)
1800 if (ventoy_plugin_check_memdisk(img
->path
))
1802 img
->menu_prefix
= "miso";
1806 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
1813 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
1815 int len
= GRUB_UINT_MAX
;
1816 const char *value
= NULL
;
1817 char name
[32] = {0};
1818 char plat
[32] = {0};
1819 char guidstr
[32] = {0};
1820 ventoy_guid guid
= VENTOY_GUID
;
1821 const char *fmt1
= NULL
;
1822 const char *fmt2
= NULL
;
1823 const char *fmt3
= NULL
;
1824 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
1825 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
1826 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
1827 const char fmtcode
[]={
1828 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
1829 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
1830 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
1831 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
1832 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
1833 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
1836 grub_memset(name
, 0, sizeof(name
));
1837 puint
[0] = grub_swap_bytes32(0x56454e54);
1838 puint
[3] = grub_swap_bytes32(0x4f4e0000);
1839 puint
[2] = grub_swap_bytes32(0x45525349);
1840 puint
[1] = grub_swap_bytes32(0x4f595f56);
1841 value
= ventoy_get_env(name
);
1843 grub_memset(name
, 0, sizeof(name
));
1844 puint
[1] = grub_swap_bytes32(0x5f544f50);
1845 puint
[0] = grub_swap_bytes32(0x56544c45);
1846 fmt1
= ventoy_get_env(name
);
1852 grub_memset(name
, 0, sizeof(name
));
1853 puint
[1] = grub_swap_bytes32(0x5f4c4654);
1854 puint
[0] = grub_swap_bytes32(0x56544c45);
1855 fmt2
= ventoy_get_env(name
);
1857 grub_memset(name
, 0, sizeof(name
));
1858 puint
[1] = grub_swap_bytes32(0x5f434c52);
1859 puint
[0] = grub_swap_bytes32(0x56544c45);
1860 fmt3
= ventoy_get_env(name
);
1862 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
1864 puint2
[0] = grub_swap_bytes32(g_ventoy_plat_data
);
1866 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
1867 #pragma GCC diagnostic push
1868 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1869 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
1870 fmt1
? fmt1
: fmtdata
,
1871 fmt2
? fmt2
: fmtdata
+ 4,
1872 value
? value
: "", plat
, guidstr
,
1873 fmt3
? fmt3
: fmtdata
+ 6);
1874 #pragma GCC diagnostic pop
1876 grub_memset(name
, 0, sizeof(name
));
1877 puint
[0] = grub_swap_bytes32(0x76746f79);
1878 puint
[2] = grub_swap_bytes32(0x656e7365);
1879 puint
[1] = grub_swap_bytes32(0x5f6c6963);
1880 ventoy_set_env(name
, guidstr
);
1885 int ventoy_check_password(const vtoy_password
*pwd
, int retry
)
1889 grub_uint8_t md5
[16];
1893 grub_memset(input
, 0, sizeof(input
));
1895 grub_printf("Enter password: ");
1898 if (pwd
->type
== VTOY_PASSWORD_TXT
)
1900 grub_password_get(input
, 128);
1901 if (grub_strcmp(pwd
->text
, input
) == 0)
1906 else if (pwd
->type
== VTOY_PASSWORD_MD5
)
1908 grub_password_get(input
, 128);
1909 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1910 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1915 else if (pwd
->type
== VTOY_PASSWORD_SALT_MD5
)
1917 offset
= (int)grub_snprintf(input
, 128, "%s", pwd
->salt
);
1918 grub_password_get(input
+ offset
, 128);
1920 grub_crypto_hash(GRUB_MD_MD5
, md5
, input
, grub_strlen(input
));
1921 if (grub_memcmp(pwd
->md5
, md5
, 16) == 0)
1927 grub_printf("Invalid password!\n\n");
1934 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
1936 img_info
*minimg
= NULL
;
1937 img_info
*img
= (img_info
*)(node
->firstiso
);
1939 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1941 if (img
->select
== 0 && (NULL
== minimg
|| ventoy_cmp_img(img
, minimg
) < 0))
1956 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1958 img_iterator_node
*Minchild
= NULL
;
1959 img_iterator_node
*child
= node
->firstchild
;
1961 while (child
&& child
->parent
== node
)
1963 if (child
->select
== 0 && (NULL
== Minchild
|| ventoy_cmp_subdir(child
, Minchild
) < 0))
1967 child
= child
->next
;
1972 Minchild
->select
= 1;
1978 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1981 img_info
*img
= NULL
;
1982 const char *dir_class
= NULL
;
1983 const char *dir_alias
= NULL
;
1984 img_iterator_node
*child
= NULL
;
1986 if (node
->isocnt
== 0 || node
->done
== 1)
1991 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1993 offset
= node
->parent
->dirlen
;
1996 if (node
== &g_img_iterator_head
)
1998 if (g_default_menu_mode
== 0)
2000 if (g_tree_view_menu_style
== 0)
2002 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2003 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2004 " echo 'return ...' \n"
2009 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2010 "menuentry \"[Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
2018 node
->dir
[node
->dirlen
- 1] = 0;
2019 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
, node
->dir
);
2022 dir_class
= "vtoydir";
2025 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
2028 if (g_tree_view_menu_style
== 0)
2030 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2031 "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2032 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
2036 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2037 "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2038 dir_alias
, dir_class
, node
->dir
+ offset
);
2043 dir_alias
= node
->dir
+ offset
;
2045 if (g_tree_view_menu_style
== 0)
2047 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2048 "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2049 "DIR", dir_alias
, dir_class
, node
->dir
+ offset
);
2053 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2054 "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" {\n",
2055 dir_alias
, dir_class
, node
->dir
+ offset
);
2059 if (g_tree_view_menu_style
== 0)
2061 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2062 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
2063 " echo 'return ...' \n"
2068 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2069 "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n "
2075 while ((child
= ventoy_get_min_child(node
)) != NULL
)
2077 ventoy_dynamic_tree_menu(child
);
2080 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
2082 if (g_tree_view_menu_style
== 0)
2084 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2085 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2088 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
2089 img
->unsupport
? "[***********] " : "",
2090 img
->alias
? img
->alias
: img
->name
, img
->class, img
,
2092 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2096 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
2097 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2100 img
->unsupport
? "[***********] " : "",
2101 img
->alias
? img
->alias
: img
->name
, img
->class, img
,
2103 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2107 if (node
!= &g_img_iterator_head
)
2109 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
2116 static int ventoy_set_default_menu(void)
2122 const char *strdata
= NULL
;
2123 img_info
*cur
= NULL
;
2124 img_info
*default_node
= NULL
;
2125 const char *default_image
= NULL
;
2127 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
2128 if (default_image
&& default_image
[0] == '/')
2130 img_len
= grub_strlen(default_image
);
2132 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2134 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
2146 if (0 == g_default_menu_mode
)
2148 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%p'\n", default_node
);
2152 def
= grub_strdup(default_image
);
2158 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "set default=%c", '\'');
2160 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2161 if (strdata
&& strdata
[0] == '/')
2163 pos
= def
+ grub_strlen(strdata
);
2174 while ((end
= grub_strchr(pos
, '/')) != NULL
)
2177 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "DIR_%s>", pos
);
2181 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "VID_%p'\n", default_node
);
2189 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2191 img_info
*next
= NULL
;
2192 img_info
*cur
= g_ventoy_img_list
;
2205 g_ventoy_img_list
= NULL
;
2206 g_ventoy_img_count
= 0;
2208 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2211 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2214 img_info
*cur
= g_ventoy_img_list
;
2218 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
2220 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
2223 img_id
= grub_strtol(args
[0], NULL
, 10);
2224 if (img_id
>= g_ventoy_img_count
)
2226 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
2229 debug("Find image %ld name \n", img_id
);
2231 while (cur
&& img_id
> 0)
2239 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
2242 debug("image name is %s\n", cur
->name
);
2244 grub_env_set(args
[1], cur
->name
);
2246 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2249 static grub_err_t
ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2253 img_info
*cur
= g_ventoy_img_list
;
2259 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2262 len
= (int)grub_strlen(args
[0]);
2266 if (len
== cur
->pathlen
&& 0 == grub_strcmp(args
[0], cur
->path
))
2275 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2278 grub_snprintf(id
, sizeof(id
), "VID_%p", cur
);
2279 grub_env_set("chosen", id
);
2280 grub_env_export("chosen");
2282 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2285 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2289 const char *id
= NULL
;
2290 img_info
*cur
= NULL
;
2294 if (argc
< 1 || argc
> 2)
2296 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
2299 id
= grub_env_get("chosen");
2301 pos
= grub_strstr(id
, "VID_");
2304 cur
= (img_info
*)(void *)grub_strtoul(pos
+ 4, NULL
, 16);
2308 cur
= g_ventoy_img_list
;
2313 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
2316 grub_env_set(args
[0], cur
->path
);
2320 grub_snprintf(value
, sizeof(value
), "%llu", (ulonglong
)(cur
->size
));
2321 grub_env_set(args
[1], value
);
2324 g_svd_replace_offset
= 0;
2326 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2330 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2334 grub_device_t dev
= NULL
;
2335 img_info
*cur
= NULL
;
2336 img_info
*tail
= NULL
;
2337 img_info
*min
= NULL
;
2338 img_info
*head
= NULL
;
2339 const char *strdata
= NULL
;
2340 char *device_name
= NULL
;
2342 img_iterator_node
*node
= NULL
;
2343 img_iterator_node
*tmp
= NULL
;
2349 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
2352 if (g_ventoy_img_list
|| g_ventoy_img_count
)
2354 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
2359 g_enumerate_time_checked
= 0;
2360 g_enumerate_start_time_ms
= grub_get_time_ms();
2362 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
2363 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2365 g_filt_dot_underscore_file
= 1;
2368 strdata
= ventoy_get_env("VTOY_SORT_CASE_SENSITIVE");
2369 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2371 g_sort_case_sensitive
= 1;
2374 device_name
= grub_file_get_device_name(args
[0]);
2380 g_enum_dev
= dev
= grub_device_open(device_name
);
2386 g_enum_fs
= fs
= grub_fs_probe(dev
);
2392 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
2394 debug("unsupported fs:<%s>\n", fs
->name
);
2395 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
2399 ventoy_set_env("vtoy_iso_fs", fs
->name
);
2401 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
2402 if (strdata
&& strdata
[0] == '1')
2404 g_default_menu_mode
= 1;
2407 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
2409 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
2411 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
2412 if (strdata
&& strdata
[0] == '/')
2414 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
2415 if (g_img_iterator_head
.dir
[len
- 1] != '/')
2417 g_img_iterator_head
.dir
[len
++] = '/';
2419 g_img_iterator_head
.dirlen
= len
;
2423 g_img_iterator_head
.dirlen
= 1;
2424 grub_strcpy(g_img_iterator_head
.dir
, "/");
2427 g_img_iterator_head
.tail
= &tail
;
2429 if (g_img_max_search_level
< 0)
2431 g_img_max_search_level
= GRUB_INT_MAX
;
2432 strdata
= ventoy_get_env("VTOY_MAX_SEARCH_LEVEL");
2433 if (strdata
&& ventoy_is_decimal(strdata
))
2435 g_img_max_search_level
= (int)grub_strtoul(strdata
, NULL
, 10);
2439 g_vtoy_file_flt
[VTOY_FILE_FLT_ISO
] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO");
2440 g_vtoy_file_flt
[VTOY_FILE_FLT_WIM
] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM");
2441 g_vtoy_file_flt
[VTOY_FILE_FLT_EFI
] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI");
2442 g_vtoy_file_flt
[VTOY_FILE_FLT_IMG
] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG");
2443 g_vtoy_file_flt
[VTOY_FILE_FLT_VHD
] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD");
2444 g_vtoy_file_flt
[VTOY_FILE_FLT_VTOY
] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY");
2446 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2448 fs
->fs_dir(dev
, node
->dir
, ventoy_collect_img_files
, node
);
2451 strdata
= ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE");
2452 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
2454 g_tree_view_menu_style
= 1;
2457 ventoy_set_default_menu();
2459 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
2461 ventoy_dynamic_tree_menu(node
);
2465 node
= g_img_iterator_head
.next
;
2473 /* sort image list by image name */
2474 while (g_ventoy_img_list
)
2476 min
= g_ventoy_img_list
;
2477 for (cur
= g_ventoy_img_list
->next
; cur
; cur
= cur
->next
)
2479 if (ventoy_cmp_img(min
, cur
) > 0)
2487 min
->prev
->next
= min
->next
;
2492 min
->next
->prev
= min
->prev
;
2495 if (min
== g_ventoy_img_list
)
2497 g_ventoy_img_list
= min
->next
;
2515 g_ventoy_img_list
= head
;
2517 if (g_default_menu_mode
== 1)
2519 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2520 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
2521 " echo 'return ...' \n"
2525 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
2527 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
2528 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n"
2531 cur
->unsupport
? "[***********] " : "",
2532 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
,
2534 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
2537 g_tree_script_buf
[g_tree_script_pos
] = 0;
2538 g_list_script_buf
[g_list_script_pos
] = 0;
2540 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
2541 grub_env_set(args
[1], buf
);
2545 check_free(device_name
, grub_free
);
2546 check_free(dev
, grub_device_close
);
2548 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2551 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
, grub_uint8_t
*signature
)
2558 device_name
= grub_file_get_device_name(filename
);
2570 pos2
= grub_strstr(pos
, ",");
2573 pos2
= grub_strstr(pos
, ")");
2581 disk
= grub_disk_open(pos
);
2584 grub_disk_read(disk
, 0, 0x180, 16, guid
);
2585 grub_disk_read(disk
, 0, 0x1b8, 4, signature
);
2586 grub_disk_close(disk
);
2593 grub_free(device_name
);
2597 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
2599 eltorito_descriptor desc
;
2601 grub_memset(&desc
, 0, sizeof(desc
));
2602 grub_file_seek(file
, 17 * 2048);
2603 grub_file_read(file
, &desc
, sizeof(desc
));
2605 if (desc
.type
!= 0 || desc
.version
!= 1)
2610 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
2611 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
2619 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
2623 grub_uint8_t buf
[512];
2624 grub_uint8_t parttype
[] = { 0x04, 0x06, 0x0B, 0x0C };
2626 grub_file_seek(file
, sector
* 2048);
2627 grub_file_read(file
, buf
, sizeof(buf
));
2629 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
2631 debug("%s efi eltorito in Validation Entry\n", file
->name
);
2635 if (buf
[0] == 0x01 && buf
[1] == 0x00)
2640 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
2642 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
2644 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2648 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
2650 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
2655 if (x86count
&& buf
[32] == 0x88 && buf
[33] == 0x04)
2657 for (i
= 0; i
< (int)(ARRAY_SIZE(parttype
)); i
++)
2659 if (buf
[36] == parttype
[i
])
2661 debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file
->name
, buf
[36]);
2667 debug("%s does not contain efi eltorito\n", file
->name
);
2671 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
2674 const char *fs
= NULL
;
2675 const char *cdprompt
= NULL
;
2677 grub_uint8_t chksum
= 0;
2680 disk
= file
->device
->disk
;
2681 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
2683 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
2684 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
2685 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
2687 pos
= grub_strstr(file
->name
, "/");
2693 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
2695 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
, param
->vtoy_disk_signature
);
2697 param
->vtoy_img_size
= file
->size
;
2699 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
2700 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
2702 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
2704 /* Windows CD/DVD prompt 0:suppress 1:reserved */
2705 param
->vtoy_reserved
[4] = 0;
2706 if (g_ventoy_chain_type
== 1) /* Windows */
2708 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
2709 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
2711 param
->vtoy_reserved
[4] = 1;
2715 fs
= ventoy_get_env("ventoy_fs_probe");
2716 if (fs
&& grub_strcmp(fs
, "udf") == 0)
2718 param
->vtoy_reserved
[3] = 1;
2721 /* calculate checksum */
2722 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
2724 chksum
+= *((grub_uint8_t
*)param
+ i
);
2726 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
2731 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2733 grub_uint32_t i
= 0;
2734 grub_uint64_t total
= 0;
2735 grub_uint64_t fileblk
= 0;
2736 ventoy_img_chunk
*chunk
= NULL
;
2738 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2740 chunk
= chunklist
->chunk
+ i
;
2742 if (chunk
->disk_start_sector
<= start
)
2744 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
2748 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
2751 fileblk
= (file
->size
+ 511) / 512;
2753 if (total
!= fileblk
)
2755 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)fileblk
);
2756 if ((file
->size
% 512) && (total
+ 1 == fileblk
))
2758 debug("maybe img file to be processed.\n");
2768 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
2772 grub_uint32_t i
= 0;
2773 grub_uint32_t sector
= 0;
2774 grub_uint32_t count
= 0;
2775 grub_off_t size
= 0;
2776 grub_off_t read
= 0;
2778 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
2779 if (fs_type
== ventoy_fs_exfat
)
2781 grub_fat_get_file_chunk(start
, file
, chunklist
);
2783 else if (fs_type
== ventoy_fs_ext
)
2785 grub_ext_get_file_chunk(start
, file
, chunklist
);
2789 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
2790 file
->read_hook_data
= chunklist
;
2792 for (size
= file
->size
; size
> 0; size
-= read
)
2794 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
2795 grub_file_read(file
, NULL
, read
);
2798 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
2800 chunklist
->chunk
[i
].disk_start_sector
+= start
;
2801 chunklist
->chunk
[i
].disk_end_sector
+= start
;
2804 if (ventoy_fs_udf
== fs_type
)
2806 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2808 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
2809 chunklist
->chunk
[i
].img_start_sector
= sector
;
2810 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2816 len
= (int)grub_strlen(file
->name
);
2817 if ((len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".img", 4) == 0) ||
2818 (len
> 4 && grub_strncasecmp(file
->name
+ len
- 4, ".vhd", 4) == 0) ||
2819 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vhdx", 5) == 0) ||
2820 (len
> 5 && grub_strncasecmp(file
->name
+ len
- 5, ".vtoy", 5) == 0))
2822 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
2824 count
= chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
;
2834 chunklist
->chunk
[i
].img_start_sector
= sector
;
2835 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
2843 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2847 grub_disk_addr_t start
;
2852 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2855 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
2858 g_conf_replace_node
= NULL
;
2859 g_conf_replace_offset
= 0;
2861 if (g_img_chunk_list
.chunk
)
2863 grub_free(g_img_chunk_list
.chunk
);
2866 if (ventoy_get_fs_type(file
->fs
->name
) >= ventoy_fs_max
)
2868 grub_file_close(file
);
2869 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Unsupported filesystem %s\n", file
->fs
->name
);
2872 /* get image chunk data */
2873 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
2874 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
2875 if (NULL
== g_img_chunk_list
.chunk
)
2877 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
2880 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
2881 g_img_chunk_list
.cur_chunk
= 0;
2883 start
= file
->device
->disk
->partition
->start
;
2885 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
2887 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
2888 grub_file_close(file
);
2892 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
2895 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
2896 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2899 static grub_err_t
ventoy_select_conf_replace(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2901 grub_uint64_t offset
= 0;
2902 grub_uint32_t align
= 0;
2903 grub_file_t file
= NULL
;
2904 conf_replace
*node
= NULL
;
2910 debug("select conf replace argc:%d\n", argc
);
2917 node
= ventoy_plugin_find_conf_replace(args
[1]);
2920 debug("Conf replace not found for %s\n", args
[1]);
2924 debug("Find conf replace for %s\n", args
[1]);
2926 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", node
->orgconf
);
2929 debug("<(loop)%s> NOT exist\n", node
->orgconf
);
2933 offset
= grub_iso9660_get_last_file_dirent_pos(file
);
2934 grub_file_close(file
);
2936 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s%s", args
[0], node
->newconf
);
2939 debug("New config file <%s%s> NOT exist\n", args
[0], node
->newconf
);
2943 align
= ((int)file
->size
+ 2047) / 2048 * 2048;
2945 if (align
> vtoy_max_replace_file_size
)
2947 debug("New config file <%s%s> too big\n", args
[0], node
->newconf
);
2951 grub_file_read(file
, g_conf_replace_new_buf
, file
->size
);
2952 g_conf_replace_new_len
= (int)file
->size
;
2953 g_conf_replace_new_len_align
= align
;
2955 g_conf_replace_node
= node
;
2956 g_conf_replace_offset
= offset
+ 2;
2958 debug("conf_replace OK: newlen: %d\n", g_conf_replace_new_len
);
2963 grub_file_close(file
);
2965 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
2968 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2973 char configfile
[128];
2974 install_template
*node
= NULL
;
2980 debug("select auto installation argc:%d\n", argc
);
2987 node
= ventoy_plugin_find_install_template(args
[0]);
2990 debug("Auto install template not found for %s\n", args
[0]);
2994 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
2996 node
->cursel
= node
->autosel
- 1;
2997 debug("Auto install template auto select %d\n", node
->autosel
);
3001 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3007 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
3008 " echo %s\n}\n", "123");
3010 for (i
= 0; i
< node
->templatenum
; i
++)
3012 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
3014 node
->templatepath
[i
].path
);
3017 g_ventoy_menu_esc
= 1;
3018 g_ventoy_suppress_esc
= 1;
3020 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
3021 grub_script_execute_sourcecode(configfile
);
3023 g_ventoy_menu_esc
= 0;
3024 g_ventoy_suppress_esc
= 0;
3028 node
->cursel
= g_ventoy_last_entry
- 1;
3030 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
3033 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3038 char configfile
[128];
3039 persistence_config
*node
;
3045 debug("select persistence argc:%d\n", argc
);
3052 node
= ventoy_plugin_find_persistent(args
[0]);
3055 debug("Persistence image not found for %s\n", args
[0]);
3059 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
3061 node
->cursel
= node
->autosel
- 1;
3062 debug("Persistence image auto select %d\n", node
->autosel
);
3066 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
3072 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
3073 " echo %s\n}\n", "123");
3075 for (i
= 0; i
< node
->backendnum
; i
++)
3077 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
3079 node
->backendpath
[i
].path
);
3083 g_ventoy_menu_esc
= 1;
3084 g_ventoy_suppress_esc
= 1;
3086 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
3087 grub_script_execute_sourcecode(configfile
);
3089 g_ventoy_menu_esc
= 0;
3090 g_ventoy_suppress_esc
= 0;
3094 node
->cursel
= g_ventoy_last_entry
- 1;
3096 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
3099 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3102 ventoy_img_chunk
*cur
;
3108 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
3110 cur
= g_img_chunk_list
.chunk
+ i
;
3111 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
3112 cur
->img_start_sector
, cur
->img_end_sector
,
3113 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
3117 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
3120 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3124 ventoy_img_chunk_list chunklist
;
3129 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3132 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
3135 /* get image chunk data */
3136 grub_memset(&chunklist
, 0, sizeof(chunklist
));
3137 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
3138 if (NULL
== chunklist
.chunk
)
3140 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
3143 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
3144 chunklist
.cur_chunk
= 0;
3146 ventoy_get_block_list(file
, &chunklist
, 0);
3148 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
3150 grub_printf("########## UNSUPPORTED ###############\n");
3153 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
3155 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
3157 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
3158 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
3161 grub_printf("\n==================================\n");
3163 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
3165 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
3166 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
3167 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
3168 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
3169 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
3173 grub_free(chunklist
.chunk
);
3174 grub_file_close(file
);
3176 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
3179 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3182 ventoy_grub_param_file_replace
*replace
= NULL
;
3190 replace
= &(g_grub_param
->file_replace
);
3191 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
3193 replace
->old_name_cnt
= 0;
3194 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
3196 replace
->old_name_cnt
++;
3197 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
3200 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
3203 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
3206 static grub_err_t
ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3209 ventoy_grub_param_file_replace
*replace
= &(g_grub_param
->file_replace
);
3215 grub_snprintf(buf
, sizeof(buf
), "%u", replace
->old_name_cnt
);
3216 grub_env_set(args
[0], buf
);
3219 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
3222 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3230 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
3231 grub_printf("%s", g_list_script_buf
);
3235 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
3236 grub_printf("%s", g_tree_script_buf
);
3242 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3244 img_info
*cur
= g_ventoy_img_list
;
3252 grub_printf("path:<%s> id=%d list_index=%d\n", cur
->path
, cur
->id
, cur
->plugin_list_index
);
3253 grub_printf("name:<%s>\n\n", cur
->name
);
3260 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3266 ventoy_plugin_dump_injection();
3271 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3277 ventoy_plugin_dump_auto_install();
3282 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3288 ventoy_plugin_dump_persistence();
3293 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3304 if (args
[0][0] == '0')
3306 return g_ventoy_memdisk_mode
? 0 : 1;
3308 else if (args
[0][0] == '1')
3310 return g_ventoy_iso_raw
? 0 : 1;
3312 else if (args
[0][0] == '2')
3314 return g_ventoy_iso_uefi_drv
? 0 : 1;
3316 else if (args
[0][0] == '3')
3318 return g_ventoy_grub2_mode
? 0 : 1;
3320 else if (args
[0][0] == '4')
3322 return g_ventoy_wimboot_mode
? 0 : 1;
3328 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3330 static int configfile_mode
= 0;
3331 char memfile
[128] = {0};
3338 * args[0]: 0:normal 1:configfile
3339 * args[1]: 0:list_buf 1:tree_buf
3344 debug("Invalid argc %d\n", argc
);
3350 if (args
[0][0] == '0')
3352 if (args
[1][0] == '0')
3354 grub_script_execute_sourcecode(g_list_script_buf
);
3358 grub_script_execute_sourcecode(g_tree_script_buf
);
3363 if (configfile_mode
)
3365 debug("Now already in F3 mode %d\n", configfile_mode
);
3369 if (args
[1][0] == '0')
3371 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3372 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
3376 g_ventoy_last_entry
= -1;
3377 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
3378 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
3381 configfile_mode
= 1;
3382 grub_script_execute_sourcecode(memfile
);
3383 configfile_mode
= 0;
3389 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3400 g_ventoy_case_insensitive
= 1;
3401 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
3402 g_ventoy_case_insensitive
= 0;
3408 grub_file_close(file
);
3414 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3419 const char *isopath
= NULL
;
3421 ventoy_mbr_head mbr
;
3428 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
3431 isopath
= grub_env_get("vtoy_iso_part");
3434 debug("isopath is null %p\n", isopath
);
3438 debug("isopath is %s\n", isopath
);
3440 for (id
= 0; id
< 30 && (find
== 0); id
++)
3442 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
3443 if (grub_strstr(isopath
, hdname
))
3445 debug("skip %s ...\n", hdname
);
3449 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
3451 disk
= grub_disk_open(hdname
);
3454 debug("%s not exist\n", hdname
);
3458 grub_memset(&mbr
, 0, sizeof(mbr
));
3459 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
3461 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
3463 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
3464 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
3467 grub_env_set(args
[0], hdname
);
3471 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
3475 debug("read %s failed\n", hdname
);
3478 grub_disk_close(disk
);
3484 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3495 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
3498 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3501 debug("failed to open file %s\n", args
[0]);
3505 buf
= grub_malloc(len
);
3512 grub_file_read(file
, buf
, len
- 1);
3514 ventoy_get_line(buf
);
3515 ventoy_set_env(args
[1], buf
);
3519 grub_check_free(buf
);
3520 grub_file_close(file
);
3525 static int ventoy_img_partition_callback (struct grub_disk
*disk
, const grub_partition_t partition
, void *data
)
3527 int *pCnt
= (int *)data
;
3532 g_part_list_pos
+= grub_snprintf(g_part_list_buf
+ g_part_list_pos
, VTOY_MAX_SCRIPT_BUF
- g_part_list_pos
,
3533 "0 %llu linear /dev/ventoy %llu\n",
3534 (ulonglong
)partition
->len
, (ulonglong
)partition
->start
);
3539 static grub_err_t
ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3542 char *device_name
= NULL
;
3543 grub_device_t dev
= NULL
;
3548 g_part_list_pos
= 0;
3549 grub_env_unset("vtoy_img_part_file");
3556 device_name
= grub_file_get_device_name(args
[0]);
3559 debug("ventoy_cmd_img_part_info failed, %s\n", args
[0]);
3563 dev
= grub_device_open(device_name
);
3566 debug("grub_device_open failed, %s\n", device_name
);
3570 grub_partition_iterate(dev
->disk
, ventoy_img_partition_callback
, &cnt
);
3572 grub_snprintf(buf
, sizeof(buf
), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong
)(ulong
)g_part_list_buf
, g_part_list_pos
);
3573 grub_env_set("vtoy_img_part_file", buf
);
3575 grub_snprintf(buf
, sizeof(buf
), "%d", cnt
);
3576 grub_env_set("vtoy_img_part_cnt", buf
);
3580 check_free(device_name
, grub_free
);
3581 check_free(dev
, grub_device_close
);
3587 static grub_err_t
ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3598 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file str \n", cmd_raw_name
);
3601 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3604 debug("failed to open file %s\n", args
[0]);
3608 buf
= grub_malloc(file
->size
+ 1);
3614 buf
[file
->size
] = 0;
3615 grub_file_read(file
, buf
, file
->size
);
3617 if (grub_strstr(buf
, args
[1]))
3624 grub_check_free(buf
);
3625 grub_file_close(file
);
3630 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3636 ventoy_iso9660_vd pvd
;
3643 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid space \n", cmd_raw_name
);
3646 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3649 debug("failed to open file %s\n", args
[0]);
3653 grub_file_seek(file
, 16 * 2048);
3654 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
3655 if (len
!= sizeof(pvd
))
3657 debug("failed to read pvd %d\n", len
);
3661 grub_memset(buf
, 0, sizeof(buf
));
3662 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
3663 ventoy_set_env(args
[1], buf
);
3665 grub_memset(buf
, 0, sizeof(buf
));
3666 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
3667 ventoy_set_env(args
[2], buf
);
3671 grub_snprintf(buf
, sizeof(buf
), "%llu", (ulonglong
)size
);
3672 ventoy_set_env(args
[3], buf
);
3675 grub_file_close(file
);
3680 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3691 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
3694 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3697 debug("failed to open file %s\n", args
[0]);
3701 grub_memset(buf
, 0, sizeof(buf
));
3702 grub_file_seek(file
, 16 * 2048 + 813);
3703 len
= (int)grub_file_read(file
, buf
, 17);
3706 debug("failed to read create date %d\n", len
);
3710 ventoy_set_env(args
[1], buf
);
3713 grub_file_close(file
);
3718 static grub_err_t
ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3724 ventoy_env_hook_root(1);
3729 static grub_err_t
ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3735 ventoy_env_hook_root(0);
3740 #ifdef GRUB_MACHINE_EFI
3741 static grub_err_t
ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3746 grub_efi_guid_t global
= GRUB_EFI_GLOBAL_VARIABLE_GUID
;
3752 var
= grub_efi_get_variable("SecureBoot", &global
, &size
);
3753 if (var
&& *var
== 1)
3761 static grub_err_t
ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3770 static grub_err_t
ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3775 grub_uint64_t FileSectors
= 0;
3776 ventoy_gpt_info
*gpt
= NULL
;
3777 ventoy_part_table
*pt
= NULL
;
3778 grub_uint8_t zeroguid
[16] = {0};
3783 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
3786 debug("failed to open file %s\n", args
[0]);
3790 if (file
->size
% 512)
3792 debug("unaligned file size: %llu\n", (ulonglong
)file
->size
);
3796 gpt
= grub_zalloc(sizeof(ventoy_gpt_info
));
3802 FileSectors
= file
->size
/ 512;
3804 grub_file_read(file
, gpt
, sizeof(ventoy_gpt_info
));
3805 if (grub_strncmp(gpt
->Head
.Signature
, "EFI PART", 8) == 0)
3807 debug("This is EFI partition table\n");
3809 for (i
= 0; i
< 128; i
++)
3811 if (grub_memcmp(gpt
->PartTbl
[i
].PartGuid
, zeroguid
, 16))
3813 if (FileSectors
< gpt
->PartTbl
[i
].LastLBA
)
3815 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i
,
3816 (ulonglong
)gpt
->PartTbl
[i
].LastLBA
, (ulonglong
)FileSectors
);
3824 debug("This is MBR partition table\n");
3826 for (i
= 0; i
< 4; i
++)
3828 pt
= gpt
->MBR
.PartTbl
+ i
;
3829 if (FileSectors
< pt
->StartSectorId
+ pt
->SectorCount
)
3831 debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i
,
3832 (ulonglong
)(pt
->StartSectorId
+ pt
->SectorCount
),
3833 (ulonglong
)FileSectors
);
3842 grub_file_close(file
);
3843 grub_check_free(gpt
);
3844 grub_errno
= GRUB_ERR_NONE
;
3848 static grub_err_t
ventoy_cmd_clear_key(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3857 for (i
= 0; i
< 500; i
++)
3859 ret
= grub_getkey_noblock();
3860 if (ret
== GRUB_TERM_NO_KEY
)
3869 grub_printf("\n\n Still have key input after clear.\n");
3877 static grub_err_t
ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3884 int image_sector_size
;
3886 ventoy_chain_head
*chain
;
3887 ventoy_img_chunk
*chunk
;
3888 ventoy_os_param
*osparam
;
3889 ventoy_image_location
*location
;
3890 ventoy_image_disk_region
*region
;
3891 struct grub_acpi_table_header
*acpi
;
3900 debug("ventoy_cmd_acpi_param %s %s\n", args
[0], args
[1]);
3902 chain
= (ventoy_chain_head
*)(ulong
)grub_strtoul(args
[0], NULL
, 16);
3908 image_sector_size
= (int)grub_strtol(args
[1], NULL
, 10);
3910 if (grub_memcmp(&g_ventoy_guid
, &(chain
->os_param
.guid
), 16))
3912 debug("Invalid ventoy guid 0x%x\n", chain
->os_param
.guid
.data1
);
3916 img_chunk_num
= chain
->img_chunk_num
;
3918 loclen
= sizeof(ventoy_image_location
) + (img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
3919 datalen
= sizeof(ventoy_os_param
) + loclen
;
3921 buflen
= sizeof(struct grub_acpi_table_header
) + datalen
;
3922 acpi
= grub_zalloc(buflen
);
3928 /* Step1: Fill acpi table header */
3929 grub_memcpy(acpi
->signature
, "VTOY", 4);
3930 acpi
->length
= buflen
;
3932 grub_memcpy(acpi
->oemid
, "VENTOY", 6);
3933 grub_memcpy(acpi
->oemtable
, "OSPARAMS", 8);
3935 acpi
->creator_id
[0] = 1;
3936 acpi
->creator_rev
= 1;
3938 /* Step2: Fill data */
3939 osparam
= (ventoy_os_param
*)(acpi
+ 1);
3940 grub_memcpy(osparam
, &chain
->os_param
, sizeof(ventoy_os_param
));
3941 osparam
->vtoy_img_location_addr
= 0;
3942 osparam
->vtoy_img_location_len
= loclen
;
3943 osparam
->chksum
= 0;
3944 osparam
->chksum
= 0x100 - grub_byte_checksum(osparam
, sizeof(ventoy_os_param
));
3946 location
= (ventoy_image_location
*)(osparam
+ 1);
3947 grub_memcpy(&location
->guid
, &osparam
->guid
, sizeof(ventoy_guid
));
3948 location
->image_sector_size
= image_sector_size
;
3949 location
->disk_sector_size
= chain
->disk_sector_size
;
3950 location
->region_count
= img_chunk_num
;
3952 region
= location
->regions
;
3953 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
3954 if (512 == image_sector_size
)
3956 for (i
= 0; i
< img_chunk_num
; i
++)
3958 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
3959 region
->image_start_sector
= chunk
->img_start_sector
* 4;
3960 region
->disk_start_sector
= chunk
->disk_start_sector
;
3967 for (i
= 0; i
< img_chunk_num
; i
++)
3969 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
3970 region
->image_start_sector
= chunk
->img_start_sector
;
3971 region
->disk_start_sector
= chunk
->disk_start_sector
;
3977 /* Step3: Fill acpi checksum */
3979 acpi
->checksum
= 0x100 - grub_byte_checksum(acpi
, acpi
->length
);
3981 /* load acpi table */
3982 grub_snprintf(cmd
, sizeof(cmd
), "acpi mem:0x%lx:size:%d", (ulong
)acpi
, acpi
->length
);
3983 grub_script_execute_sourcecode(cmd
);
3987 VENTOY_CMD_RETURN(0);
3990 static grub_err_t
ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
3996 g_ventoy_last_entry_back
= g_ventoy_last_entry
;
3997 g_ventoy_last_entry
= -1;
4002 static grub_err_t
ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4008 g_ventoy_last_entry
= g_ventoy_last_entry_back
;
4013 static int ventoy_lib_module_callback(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
4015 const char *pos
= filename
+ 1;
4023 if ((*(pos
- 1) >= '0' && *(pos
- 1) <= '9') && (*(pos
+ 1) >= '0' && *(pos
+ 1) <= '9'))
4025 grub_strncpy((char *)data
, filename
, 128);
4036 static grub_err_t
ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4039 char *device_name
= NULL
;
4040 grub_device_t dev
= NULL
;
4041 grub_fs_t fs
= NULL
;
4042 char buf
[128] = {0};
4048 debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc
);
4052 debug("ventoy_cmd_lib_module_ver %s %s %s\n", args
[0], args
[1], args
[2]);
4054 device_name
= grub_file_get_device_name(args
[0]);
4057 debug("grub_file_get_device_name failed, %s\n", args
[0]);
4061 dev
= grub_device_open(device_name
);
4064 debug("grub_device_open failed, %s\n", device_name
);
4068 fs
= grub_fs_probe(dev
);
4071 debug("grub_fs_probe failed, %s\n", device_name
);
4075 fs
->fs_dir(dev
, args
[1], ventoy_lib_module_callback
, buf
);
4079 ventoy_set_env(args
[2], buf
);
4086 check_free(device_name
, grub_free
);
4087 check_free(dev
, grub_device_close
);
4092 int ventoy_load_part_table(const char *diskname
)
4099 g_ventoy_part_info
= grub_zalloc(sizeof(ventoy_gpt_info
));
4100 if (!g_ventoy_part_info
)
4105 disk
= grub_disk_open(diskname
);
4108 debug("Failed to open disk %s\n", diskname
);
4112 g_ventoy_disk_size
= disk
->total_sectors
* (1U << disk
->log_sector_size
);
4114 grub_disk_read(disk
, 0, 0, sizeof(ventoy_gpt_info
), g_ventoy_part_info
);
4115 grub_disk_close(disk
);
4117 grub_snprintf(name
, sizeof(name
), "%s,1", diskname
);
4118 dev
= grub_device_open(name
);
4121 /* Check for official Ventoy device */
4122 ret
= ventoy_check_official_device(dev
);
4123 grub_device_close(dev
);
4131 g_ventoy_disk_part_size
[0] = ventoy_get_vtoy_partsize(0);
4132 g_ventoy_disk_part_size
[1] = ventoy_get_vtoy_partsize(1);
4137 static grub_err_t
ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4144 ret
= ventoy_load_part_table(args
[0]);
4150 g_ventoy_disk_part_size
[0] = ventoy_get_vtoy_partsize(0);
4151 g_ventoy_disk_part_size
[1] = ventoy_get_vtoy_partsize(1);
4156 static grub_err_t
ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4159 const char *vcfg
= NULL
;
4164 vcfg
= ventoy_plugin_get_custom_boot(args
[0]);
4167 debug("custom boot <%s>:<%s>\n", args
[0], vcfg
);
4168 grub_env_set(args
[1], vcfg
);
4173 debug("custom boot <%s>:<NOT FOUND>\n", args
[0]);
4181 static grub_err_t
ventoy_cmd_part_exist(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4184 grub_uint8_t zeroguid
[16] = {0};
4189 id
= (int)grub_strtoul(args
[0], NULL
, 10);
4192 if (grub_memcmp(g_ventoy_part_info
->Head
.Signature
, "EFI PART", 8) == 0)
4194 if (id
>= 1 && id
<= 128)
4196 if (grub_memcmp(g_ventoy_part_info
->PartTbl
[id
- 1].PartGuid
, zeroguid
, 16))
4204 if (id
>= 1 && id
<= 4)
4206 if (g_ventoy_part_info
->MBR
.PartTbl
[id
- 1].FsFlag
)
4216 static grub_err_t
ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4219 char *device_name
= NULL
;
4220 grub_device_t dev
= NULL
;
4221 grub_fs_t fs
= NULL
;
4226 debug("get fs label for %s\n", args
[0]);
4230 debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc
);
4234 device_name
= grub_file_get_device_name(args
[0]);
4237 debug("grub_file_get_device_name failed, %s\n", args
[0]);
4241 dev
= grub_device_open(device_name
);
4244 debug("grub_device_open failed, %s\n", device_name
);
4248 fs
= grub_fs_probe(dev
);
4249 if (NULL
== fs
|| NULL
== fs
->fs_label
)
4251 debug("grub_fs_probe failed, %s %p %p\n", device_name
, fs
, fs
->fs_label
);
4255 fs
->fs_label(dev
, &label
);
4258 debug("label=<%s>\n", label
);
4259 ventoy_set_env(args
[1], label
);
4267 check_free(device_name
, grub_free
);
4268 check_free(dev
, grub_device_close
);
4273 static int ventoy_fs_enum_1st_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
4277 grub_snprintf((char *)data
, 256, "%s", filename
);
4284 static int ventoy_fs_enum_1st_dir(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
4286 if (info
->dir
&& filename
&& filename
[0] != '.')
4288 grub_snprintf((char *)data
, 256, "%s", filename
);
4295 static grub_err_t
ventoy_fs_enum_1st_child(int argc
, char **args
, grub_fs_dir_hook_t hook
)
4298 char *device_name
= NULL
;
4299 grub_device_t dev
= NULL
;
4300 grub_fs_t fs
= NULL
;
4301 char name
[256] ={0};
4305 debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc
);
4309 device_name
= grub_file_get_device_name(args
[0]);
4312 debug("grub_file_get_device_name failed, %s\n", args
[0]);
4316 dev
= grub_device_open(device_name
);
4319 debug("grub_device_open failed, %s\n", device_name
);
4323 fs
= grub_fs_probe(dev
);
4326 debug("grub_fs_probe failed, %s\n", device_name
);
4330 fs
->fs_dir(dev
, args
[1], hook
, name
);
4333 ventoy_set_env(args
[2], name
);
4340 check_free(device_name
, grub_free
);
4341 check_free(dev
, grub_device_close
);
4346 static grub_err_t
ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4349 return ventoy_fs_enum_1st_child(argc
, args
, ventoy_fs_enum_1st_file
);
4352 static grub_err_t
ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4355 return ventoy_fs_enum_1st_child(argc
, args
, ventoy_fs_enum_1st_dir
);
4358 static grub_err_t
ventoy_cmd_basename(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4368 debug("ventoy_cmd_basename, invalid param num %d\n", argc
);
4372 for (pos
= args
[0]; *pos
; pos
++)
4386 grub_env_set(args
[1], args
[0]);
4396 static grub_err_t
ventoy_cmd_basefile(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4406 debug("ventoy_cmd_basefile, invalid param num %d\n", argc
);
4411 len
= (int)grub_strlen(buf
);
4412 for (i
= len
; i
> 0; i
--)
4414 if (buf
[i
- 1] == '/')
4416 grub_env_set(args
[1], buf
+ i
);
4421 grub_env_set(args
[1], buf
);
4426 static grub_err_t
ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4428 struct grub_video_mode_info info
;
4435 if (!g_video_mode_list
)
4437 ventoy_enum_video_mode();
4440 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
4442 grub_snprintf(buf
, sizeof(buf
), "Resolution (%ux%u)", info
.width
, info
.height
);
4446 grub_snprintf(buf
, sizeof(buf
), "Resolution (0x0)");
4449 grub_env_set("VTOY_CUR_VIDEO_MODE", buf
);
4451 grub_snprintf(buf
, sizeof(buf
), "%d", g_video_mode_num
);
4452 grub_env_set("VTOY_VIDEO_MODE_NUM", buf
);
4454 VENTOY_CMD_RETURN(0);
4457 static grub_err_t
vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4459 struct grub_video_mode_info info
;
4466 if (grub_video_get_info(&info
) == GRUB_ERR_NONE
)
4468 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u", info
.width
, info
.height
, info
.bpp
);
4472 grub_snprintf(buf
, sizeof(buf
), "0x0x0");
4475 grub_env_set(args
[0], buf
);
4477 VENTOY_CMD_RETURN(0);
4480 static grub_err_t
ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4488 if (!g_video_mode_list
)
4493 id
= (int)grub_strtoul(args
[0], NULL
, 10);
4494 if (id
< g_video_mode_num
)
4496 grub_snprintf(buf
, sizeof(buf
), "%ux%ux%u",
4497 g_video_mode_list
[id
].width
, g_video_mode_list
[id
].height
, g_video_mode_list
[id
].bpp
);
4500 grub_env_set(args
[1], buf
);
4502 VENTOY_CMD_RETURN(0);
4505 static grub_err_t
ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4508 grub_uint32_t loadsector
= 0;
4511 grub_uint32_t boot_catlog
= 0;
4512 grub_uint8_t buf
[512];
4518 debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc
);
4522 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
4525 debug("failed to open %s\n", args
[0]);
4529 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
4530 if (boot_catlog
== 0)
4532 debug("No bootcatlog found\n");
4533 grub_file_close(file
);
4537 grub_memset(buf
, 0, sizeof(buf
));
4538 grub_file_seek(file
, boot_catlog
* 2048);
4539 grub_file_read(file
, buf
, sizeof(buf
));
4540 grub_file_close(file
);
4542 for (i
= 0; i
< sizeof(buf
); i
+= 32)
4544 if ((buf
[i
] == 0 || buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
4546 if (buf
[i
+ 32] == 0x88)
4548 loadsector
= *(grub_uint32_t
*)(buf
+ i
+ 32 + 8);
4549 grub_snprintf(value
, sizeof(value
), "%u", loadsector
* 4); //change to sector size 512
4555 if (loadsector
== 0)
4557 debug("No EFI eltorito info found\n");
4561 debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value
);
4562 grub_env_set(args
[1], value
);
4563 VENTOY_CMD_RETURN(0);
4566 static int ventoy_collect_replace_initrd(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
4571 replace_fs_dir
*pfsdir
= (replace_fs_dir
*)data
;
4573 if (pfsdir
->initrd
[0])
4578 curpos
= pfsdir
->curpos
;
4579 len
= grub_strlen(filename
);
4583 if ((len
== 1 && filename
[0] == '.') ||
4584 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
4589 //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename);
4592 printlen
= grub_snprintf(pfsdir
->fullpath
+ curpos
, 512 - curpos
, "%s/", filename
);
4593 pfsdir
->curpos
= curpos
+ printlen
;
4594 pfsdir
->fs
->fs_dir(pfsdir
->dev
, pfsdir
->fullpath
, ventoy_collect_replace_initrd
, pfsdir
);
4595 pfsdir
->curpos
= curpos
;
4596 pfsdir
->fullpath
[curpos
] = 0;
4600 //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename);
4603 /* We consider the xxx.img file bigger than 32MB is the initramfs file */
4604 if (len
> 4 && grub_strncmp(filename
+ len
- 4, ".img", 4) == 0)
4606 if (info
->size
> 32 * VTOY_SIZE_1MB
)
4608 grub_snprintf(pfsdir
->initrd
, sizeof(pfsdir
->initrd
), "%s%s", pfsdir
->fullpath
, filename
);
4617 static grub_err_t
ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4621 char *device_name
= NULL
;
4622 grub_device_t dev
= NULL
;
4623 grub_fs_t fs
= NULL
;
4624 replace_fs_dir
*pfsdir
= NULL
;
4630 debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc
);
4634 pfsdir
= grub_zalloc(sizeof(replace_fs_dir
));
4640 device_name
= grub_file_get_device_name(args
[0]);
4646 dev
= grub_device_open(device_name
);
4652 fs
= grub_fs_probe(dev
);
4661 pfsdir
->fullpath
[0] = '/';
4662 fs
->fs_dir(dev
, "/", ventoy_collect_replace_initrd
, pfsdir
);
4664 if (pfsdir
->initrd
[0])
4666 debug("Replace initrd <%s> <%d %d>\n", pfsdir
->initrd
, pfsdir
->dircnt
, pfsdir
->filecnt
);
4668 for (i
= 0; i
< (int)sizeof(pfsdir
->initrd
) && pfsdir
->initrd
[i
]; i
++)
4670 if (pfsdir
->initrd
[i
] == '/')
4672 pfsdir
->initrd
[i
] = '\\';
4676 pos
= (pfsdir
->initrd
[0] == '\\') ? pfsdir
->initrd
+ 1 : pfsdir
->initrd
;
4677 grub_env_set(args
[1], pos
);
4681 debug("Replace initrd NOT found <%s> <%d %d>\n", args
[0], pfsdir
->dircnt
, pfsdir
->filecnt
);
4686 grub_check_free(pfsdir
);
4687 grub_check_free(device_name
);
4688 check_free(dev
, grub_device_close
);
4690 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
4693 static grub_err_t
ventoy_cmd_push_pager(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4695 const char *pager
= NULL
;
4701 pager
= grub_env_get("pager");
4705 grub_env_set("pager", "1");
4707 else if (pager
[0] == '1')
4713 grub_snprintf(g_old_pager
, sizeof(g_old_pager
), "%s", pager
);
4715 grub_env_set("pager", "1");
4718 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
4721 static grub_err_t
ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4727 if (g_pager_flag
== 1)
4729 grub_env_unset("pager");
4731 else if (g_pager_flag
== 2)
4733 grub_env_set("pager", g_old_pager
);
4736 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
4739 static int ventoy_chk_case_file(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
4741 if (g_json_case_mis_path
[0])
4746 if (0 == info
->dir
&& grub_strncasecmp(filename
, "ventoy.json", 11) == 0)
4748 grub_snprintf(g_json_case_mis_path
, 32, "%s/%s", (char *)data
, filename
);
4754 static int ventoy_chk_case_dir(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
4757 chk_case_fs_dir
*fs_dir
= (chk_case_fs_dir
*)data
;
4759 if (g_json_case_mis_path
[0])
4764 if (info
->dir
&& (filename
[0] == 'v' || filename
[0] == 'V'))
4766 if (grub_strncasecmp(filename
, "ventoy", 6) == 0)
4768 grub_snprintf(path
, sizeof(path
), "/%s", filename
);
4769 fs_dir
->fs
->fs_dir(fs_dir
->dev
, path
, ventoy_chk_case_file
, path
);
4770 if (g_json_case_mis_path
[0])
4780 static grub_err_t
ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4783 char *device_name
= NULL
;
4784 grub_device_t dev
= NULL
;
4785 grub_fs_t fs
= NULL
;
4786 chk_case_fs_dir fs_dir
;
4792 device_name
= grub_file_get_device_name(args
[0]);
4798 dev
= grub_device_open(device_name
);
4804 fs
= grub_fs_probe(dev
);
4810 fstype
= ventoy_get_fs_type(fs
->name
);
4811 if (fstype
== ventoy_fs_fat
|| fstype
== ventoy_fs_exfat
|| fstype
>= ventoy_fs_max
)
4816 g_json_case_mis_path
[0] = 0;
4819 fs
->fs_dir(dev
, "/", ventoy_chk_case_dir
, &fs_dir
);
4821 if (g_json_case_mis_path
[0])
4823 grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path
);
4828 grub_check_free(device_name
);
4829 check_free(dev
, grub_device_close
);
4831 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
4834 static grub_err_t
grub_cmd_gptpriority(grub_extcmd_context_t ctxt
, int argc
, char **args
)
4837 grub_partition_t part
;
4838 char priority_str
[3]; /* Maximum value 15 */
4842 if (argc
< 2 || argc
> 3)
4843 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
4844 "gptpriority DISKNAME PARTITIONNUM [VARNAME]");
4846 /* Open the disk if it exists */
4847 disk
= grub_disk_open (args
[0]);
4850 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
4854 part
= grub_partition_probe (disk
, args
[1]);
4857 grub_disk_close (disk
);
4858 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
4859 "No such partition");
4862 if (grub_strcmp (part
->partmap
->name
, "gpt"))
4864 grub_disk_close (disk
);
4865 return grub_error (GRUB_ERR_BAD_PART_TABLE
,
4866 "Not a GPT partition");
4869 grub_snprintf (priority_str
, sizeof(priority_str
), "%u",
4870 (grub_uint32_t
)((part
->gpt_attrib
>> 48) & 0xfULL
));
4874 grub_env_set (args
[2], priority_str
);
4875 grub_env_export (args
[2]);
4879 grub_printf ("Priority is %s\n", priority_str
);
4882 grub_disk_close (disk
);
4883 return GRUB_ERR_NONE
;
4888 /* <BEGIN>: Deleted by longpanda, 20210916 PN:XX LABEL:XX */
4890 void ventoy_tip_set_menu_label(const char *vid
)
4894 g_ventoy_tip_msg1
= g_ventoy_tip_msg2
= NULL
;
4897 node
= (img_info
*)(void *)grub_strtoul(vid
+ 4, NULL
, 16);
4900 g_ventoy_tip_msg1
= node
->tip1
;
4901 g_ventoy_tip_msg2
= node
->tip2
;
4906 /* <END> : Deleted by longpanda, 20210916 PN:XX LABEL:XX */
4908 int ventoy_env_init(void)
4912 grub_env_set("vtdebug_flag", "");
4914 g_part_list_buf
= grub_malloc(VTOY_PART_BUF_LEN
);
4915 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4916 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
4917 g_conf_replace_new_buf
= grub_malloc(vtoy_max_replace_file_size
);
4919 ventoy_filt_register(0, ventoy_wrapper_open
);
4921 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
4924 g_grub_param
->grub_env_get
= grub_env_get
;
4925 g_grub_param
->grub_env_set
= (grub_env_set_pf
)grub_env_set
;
4926 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
4927 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
4928 grub_env_set("env_param", buf
);
4929 grub_env_set("ventoy_env_param", buf
);
4931 grub_env_export("env_param");
4932 grub_env_export("ventoy_env_param");
4935 grub_snprintf(buf
, sizeof(buf
), "0x%lx", (ulong
)g_vtoy_winpeshl_ini
);
4936 grub_env_set("vtoy_winpeshl_ini_addr", buf
);
4938 grub_snprintf(buf
, sizeof(buf
), "%d", (int)grub_strlen(g_vtoy_winpeshl_ini
));
4939 grub_env_set("vtoy_winpeshl_ini_size", buf
);
4941 grub_env_export("vtoy_winpeshl_ini_addr");
4942 grub_env_export("vtoy_winpeshl_ini_size");
4944 grub_snprintf(buf
, sizeof(buf
), "0x%lx", (ulong
)ventoy_chain_file_size
);
4945 grub_env_set("vtoy_chain_file_size", buf
);
4946 grub_env_export("vtoy_chain_file_size");
4948 grub_snprintf(buf
, sizeof(buf
), "0x%lx", (ulong
)ventoy_chain_file_read
);
4949 grub_env_set("vtoy_chain_file_read", buf
);
4950 grub_env_export("vtoy_chain_file_read");
4957 static cmd_para ventoy_cmds
[] =
4959 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
4960 { "vt_mod", ventoy_cmd_mod
, 0, NULL
, "{Int} {Int} {Var}", "mod integer variable", NULL
},
4961 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
4962 { "vt_str_begin", ventoy_cmd_strbegin
, 0, NULL
, "", "", NULL
},
4963 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4964 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
4965 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
4966 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
4967 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
4968 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
4969 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
4970 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
4971 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
4972 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
4973 { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path
, 0, NULL
, "{var}", "select chosen img path", NULL
},
4974 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
4975 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
4976 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
4977 { "vt_load_vhdboot", ventoy_cmd_load_vhdboot
, 0, NULL
, "", "", NULL
},
4978 { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot
, 0, NULL
, "", "", NULL
},
4979 { "vt_raw_chain_data", ventoy_cmd_raw_chain_data
, 0, NULL
, "", "", NULL
},
4980 { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type
, 0, NULL
, "", "", NULL
},
4981 { "vt_check_custom_boot", ventoy_cmd_check_custom_boot
, 0, NULL
, "", "", NULL
},
4982 { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot
, 0, NULL
, "", "", NULL
},
4984 { "vt_skip_svd", ventoy_cmd_skip_svd
, 0, NULL
, "", "", NULL
},
4985 { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64
, 0, NULL
, "", "", NULL
},
4986 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
4987 { "vt_trailer_cpio", ventoy_cmd_trailer_cpio
, 0, NULL
, "", "", NULL
},
4988 { "vt_push_last_entry", ventoy_cmd_push_last_entry
, 0, NULL
, "", "", NULL
},
4989 { "vt_pop_last_entry", ventoy_cmd_pop_last_entry
, 0, NULL
, "", "", NULL
},
4990 { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver
, 0, NULL
, "", "", NULL
},
4992 { "vt_load_part_table", ventoy_cmd_load_part_table
, 0, NULL
, "", "", NULL
},
4993 { "vt_check_part_exist", ventoy_cmd_part_exist
, 0, NULL
, "", "", NULL
},
4994 { "vt_get_fs_label", ventoy_cmd_get_fs_label
, 0, NULL
, "", "", NULL
},
4995 { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file
, 0, NULL
, "", "", NULL
},
4996 { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir
, 0, NULL
, "", "", NULL
},
4997 { "vt_file_basename", ventoy_cmd_basename
, 0, NULL
, "", "", NULL
},
4998 { "vt_file_basefile", ventoy_cmd_basefile
, 0, NULL
, "", "", NULL
},
4999 { "vt_enum_video_mode", ventoy_cmd_enum_video_mode
, 0, NULL
, "", "", NULL
},
5000 { "vt_get_video_mode", ventoy_cmd_get_video_mode
, 0, NULL
, "", "", NULL
},
5001 { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode
, 0, NULL
, "", "", NULL
},
5004 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
5005 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
5006 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
5007 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
5008 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
5009 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
5010 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
5011 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
5012 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
5013 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
5014 { "vt_select_conf_replace", ventoy_select_conf_replace
, 0, NULL
, "", "", NULL
},
5016 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
5017 { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet
, 0, NULL
, "", "", NULL
},
5018 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
5019 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
5020 { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem
, 0, NULL
, "", "", NULL
},
5021 { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk
, 0, NULL
, "", "", NULL
},
5022 { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso
, 0, NULL
, "", "", NULL
},
5024 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
5025 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
5026 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
5027 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
5028 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
5029 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
5030 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
5031 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
5032 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
5033 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
5035 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
5036 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
5037 { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data
, 0, NULL
, "", "", NULL
},
5038 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
5039 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
5040 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
5041 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
5042 { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable
, 0, NULL
, "", "", NULL
},
5043 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
5045 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
5046 { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt
, 0, NULL
, "", "", NULL
},
5047 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
5048 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
5051 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
5052 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
5053 { "vt_check_password", ventoy_cmd_check_password
, 0, NULL
, "", "", NULL
},
5055 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
5056 { "vt_file_strstr", ventoy_cmd_file_strstr
, 0, NULL
, "", "", NULL
},
5057 { "vt_img_part_info", ventoy_cmd_img_part_info
, 0, NULL
, "", "", NULL
},
5060 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
5061 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
5062 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
5063 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
5064 { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf
, 0, NULL
, "", "", NULL
},
5065 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
5066 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
5067 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
5068 { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc
, 0, NULL
, "", "", NULL
},
5069 { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko
, 0, NULL
, "", "", NULL
},
5070 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
5072 { "vt_img_hook_root", ventoy_cmd_img_hook_root
, 0, NULL
, "", "", NULL
},
5073 { "vt_img_unhook_root", ventoy_cmd_img_unhook_root
, 0, NULL
, "", "", NULL
},
5074 { "vt_acpi_param", ventoy_cmd_acpi_param
, 0, NULL
, "", "", NULL
},
5075 { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var
, 0, NULL
, "", "", NULL
},
5076 { "vt_clear_key", ventoy_cmd_clear_key
, 0, NULL
, "", "", NULL
},
5077 { "vt_img_check_range", ventoy_cmd_img_check_range
, 0, NULL
, "", "", NULL
},
5078 { "vt_is_pe64", ventoy_cmd_is_pe64
, 0, NULL
, "", "", NULL
},
5079 { "vt_sel_wimboot", ventoy_cmd_sel_wimboot
, 0, NULL
, "", "", NULL
},
5080 { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt
, 0, NULL
, "", "", NULL
},
5081 { "vt_set_theme", ventoy_cmd_set_theme
, 0, NULL
, "", "", NULL
},
5083 { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset
, 0, NULL
, "", "", NULL
},
5084 { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd
, 0, NULL
, "", "", NULL
},
5085 { "vt_push_pager", ventoy_cmd_push_pager
, 0, NULL
, "", "", NULL
},
5086 { "vt_pop_pager", ventoy_cmd_pop_pager
, 0, NULL
, "", "", NULL
},
5087 { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase
, 0, NULL
, "", "", NULL
},
5088 { "vt_append_extra_sector", ventoy_cmd_append_ext_sector
, 0, NULL
, "", "", NULL
},
5089 { "gptpriority", grub_cmd_gptpriority
, 0, NULL
, "", "", NULL
},
5092 int ventoy_register_all_cmd(void)
5095 cmd_para
*cur
= NULL
;
5097 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
5099 cur
= ventoy_cmds
+ i
;
5100 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
5101 cur
->summary
, cur
->description
, cur
->parser
);
5107 int ventoy_unregister_all_cmd(void)
5111 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
5113 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);