1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <grub/types.h>
22 #include <grub/misc.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
36 #include <grub/misc.h>
37 #ifdef GRUB_MACHINE_EFI
38 #include <grub/efi/efi.h>
40 #include <grub/time.h>
41 #include <grub/relocator.h>
42 #include <grub/ventoy.h>
43 #include "ventoy_def.h"
45 GRUB_MOD_LICENSE ("GPLv3+");
47 int g_ventoy_debug
= 0;
48 static int g_efi_os
= 0xFF;
49 initrd_info
*g_initrd_img_list
= NULL
;
50 initrd_info
*g_initrd_img_tail
= NULL
;
51 int g_initrd_img_count
= 0;
52 int g_valid_initrd_count
= 0;
53 int g_default_menu_mode
= 0;
54 int g_filt_dot_underscore_file
= 0;
55 static grub_file_t g_old_file
;
58 char g_img_swap_tmp_buf
[1024];
59 img_info g_img_swap_tmp
;
60 img_info
*g_ventoy_img_list
= NULL
;
62 int g_ventoy_img_count
= 0;
64 grub_device_t g_enum_dev
= NULL
;
65 grub_fs_t g_enum_fs
= NULL
;
66 img_iterator_node g_img_iterator_head
;
67 img_iterator_node
*g_img_iterator_tail
= NULL
;
69 grub_uint8_t g_ventoy_break_level
= 0;
70 grub_uint8_t g_ventoy_debug_level
= 0;
71 grub_uint8_t g_ventoy_chain_type
= 0;
73 grub_uint8_t
*g_ventoy_cpio_buf
= NULL
;
74 grub_uint32_t g_ventoy_cpio_size
= 0;
75 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
76 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
78 ventoy_grub_param
*g_grub_param
= NULL
;
80 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
82 ventoy_img_chunk_list g_img_chunk_list
;
84 int g_wimboot_enable
= 0;
85 ventoy_img_chunk_list g_wimiso_chunk_list
;
86 char *g_wimiso_path
= NULL
;
88 static char *g_tree_script_buf
= NULL
;
89 static int g_tree_script_pos
= 0;
91 static char *g_list_script_buf
= NULL
;
92 static int g_list_script_pos
= 0;
94 static const char *g_menu_class
[] =
96 "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg"
99 static const char *g_menu_prefix
[] =
101 "iso", "wim", "efi", "img"
104 void ventoy_debug(const char *fmt
, ...)
108 va_start (args
, fmt
);
109 grub_vprintf (fmt
, args
);
113 int ventoy_is_efi_os(void)
117 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
123 static int ventoy_get_fs_type(const char *fs
)
127 return ventoy_fs_max
;
129 else if (grub_strncmp(fs
, "exfat", 5) == 0)
131 return ventoy_fs_exfat
;
133 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
135 return ventoy_fs_ntfs
;
137 else if (grub_strncmp(fs
, "ext", 3) == 0)
139 return ventoy_fs_ext
;
141 else if (grub_strncmp(fs
, "xfs", 3) == 0)
143 return ventoy_fs_xfs
;
145 else if (grub_strncmp(fs
, "udf", 3) == 0)
147 return ventoy_fs_udf
;
149 else if (grub_strncmp(fs
, "fat", 3) == 0)
151 return ventoy_fs_fat
;
154 return ventoy_fs_max
;
157 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
176 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
178 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
182 static grub_err_t
ventoy_fs_close(grub_file_t file
)
184 grub_file_close(g_old_file
);
185 grub_free(file
->data
);
193 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
197 static struct grub_fs vtoy_fs
=
202 .fs_read
= ventoy_fs_read
,
203 .fs_close
= ventoy_fs_close
,
213 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
219 file
->data
= grub_malloc(rawFile
->size
+ 4096);
225 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
226 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
228 g_old_file
= rawFile
;
230 file
->size
= rawFile
->size
+ len
;
231 file
->device
= rawFile
->device
;
233 file
->not_easily_seekable
= 1;
238 static int ventoy_check_decimal_var(const char *name
, long *value
)
240 const char *value_str
= NULL
;
242 value_str
= grub_env_get(name
);
243 if (NULL
== value_str
)
245 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
248 if (!ventoy_is_decimal(value_str
))
250 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
253 *value
= grub_strtol(value_str
, NULL
, 10);
255 return GRUB_ERR_NONE
;
258 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
262 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
265 if (0 == grub_strcmp(args
[0], "on"))
268 grub_env_set("vtdebug_flag", "debug");
273 grub_env_set("vtdebug_flag", "");
276 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
279 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
283 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
285 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
286 grub_printf(" level:\r\n");
287 grub_printf(" 01/11: busybox / (+cat log)\r\n");
288 grub_printf(" 02/12: initrd / (+cat log)\r\n");
289 grub_printf(" 03/13: hook / (+cat log)\r\n");
291 grub_printf(" debug:\r\n");
292 grub_printf(" 0: debug is on\r\n");
293 grub_printf(" 1: debug is off\r\n");
295 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
298 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
300 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
302 g_ventoy_debug_level
= 1;
305 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
308 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
313 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
315 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
318 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
323 value_long
+= grub_strtol(args
[1], NULL
, 10);
325 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
326 grub_env_set(args
[0], buf
);
328 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
331 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
346 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
349 debug("failed to open file <%s> for udf check\n", args
[0]);
353 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
355 grub_env_set(args
[1], buf
);
357 grub_file_close(file
);
363 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
371 g_wimboot_enable
= 0;
372 grub_check_free(g_wimiso_path
);
373 grub_check_free(g_wimiso_chunk_list
.chunk
);
375 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
381 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
382 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
383 if (NULL
== g_wimiso_chunk_list
.chunk
)
385 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
388 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
389 g_wimiso_chunk_list
.cur_chunk
= 0;
391 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
393 g_wimboot_enable
= 1;
394 g_wimiso_path
= grub_strdup(args
[0]);
396 grub_file_close(file
);
401 static grub_err_t
ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
418 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
421 debug("failed to open file <%s> for udf check\n", args
[0]);
425 #ifdef GRUB_MACHINE_EFI
426 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
428 buf
= (char *)grub_malloc(file
->size
);
431 grub_file_read(file
, buf
, file
->size
);
433 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
434 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
435 grub_env_set(name
, value
);
437 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
438 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
439 grub_env_set(name
, value
);
441 grub_file_close(file
);
447 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
456 if (args
[0][0] == '1')
458 grub_iso9660_set_nojoliet(1);
462 grub_iso9660_set_nojoliet(0);
468 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
473 grub_uint8_t buf
[32];
484 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
487 debug("failed to open file <%s> for udf check\n", args
[0]);
491 for (i
= 16; i
< 32; i
++)
493 grub_file_seek(file
, i
* 2048);
494 grub_file_read(file
, buf
, sizeof(buf
));
502 grub_file_seek(file
, i
* 2048);
503 grub_file_read(file
, buf
, sizeof(buf
));
505 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
508 grub_file_seek(file
, i
* 2048);
509 grub_file_read(file
, buf
, sizeof(buf
));
511 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
512 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
518 grub_file_close(file
);
520 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
525 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
527 long value_long1
= 0;
528 long value_long2
= 0;
530 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
532 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
535 value_long1
= grub_strtol(args
[0], NULL
, 10);
536 value_long2
= grub_strtol(args
[2], NULL
, 10);
538 if (0 == grub_strcmp(args
[1], "eq"))
540 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
542 else if (0 == grub_strcmp(args
[1], "ne"))
544 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
546 else if (0 == grub_strcmp(args
[1], "gt"))
548 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
550 else if (0 == grub_strcmp(args
[1], "lt"))
552 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
554 else if (0 == grub_strcmp(args
[1], "ge"))
556 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
558 else if (0 == grub_strcmp(args
[1], "le"))
560 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
564 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
570 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
577 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
580 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
581 pos
= grub_strstr(buf
, ",");
587 grub_env_set(args
[1], buf
);
589 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
592 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
598 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
604 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
607 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
609 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
610 if (0 == grub_script_execute_sourcecode(buf
))
612 debug("file %s exist, ventoy_compatible YES\n", buf
);
613 grub_env_set("ventoy_compatible", "YES");
614 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
618 debug("file %s NOT exist\n", buf
);
622 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
623 pos
= grub_strstr(buf
, ")");
629 disk
= grub_disk_open(buf
);
632 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
633 grub_disk_close(disk
);
635 g_img_swap_tmp_buf
[703] = 0;
636 for (i
= 319; i
< 703; i
++)
638 if (g_img_swap_tmp_buf
[i
] == 'V' &&
639 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
641 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
642 grub_env_set("ventoy_compatible", "YES");
643 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
649 debug("failed to open disk <%s>\n", buf
);
652 grub_env_set("ventoy_compatible", "NO");
653 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
656 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
662 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
667 if (grub_islower(c1
))
672 if (grub_islower(c2
))
686 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
688 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
690 grub_memcpy(img1
, img2
, sizeof(img_info
));
691 img1
->next
= g_img_swap_tmp
.next
;
692 img1
->prev
= g_img_swap_tmp
.prev
;
694 g_img_swap_tmp
.next
= img2
->next
;
695 g_img_swap_tmp
.prev
= img2
->prev
;
696 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
699 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
703 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
708 for (i
= 0; i
< namelen
; i
++)
710 if (filename
[i
] == ' ' || filename
[i
] == '\t')
715 if ((grub_uint8_t
)(filename
[i
]) >= 127)
724 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
728 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
738 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
746 img_iterator_node
*tmp
;
747 img_iterator_node
*new_node
;
748 img_iterator_node
*node
= (img_iterator_node
*)data
;
750 len
= grub_strlen(filename
);
754 if ((len
== 1 && filename
[0] == '.') ||
755 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
760 if (!ventoy_img_name_valid(filename
, len
))
765 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
770 new_node
= grub_zalloc(sizeof(img_iterator_node
));
773 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
775 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
778 debug("Directory %s ignored...\n", new_node
->dir
);
783 new_node
->tail
= node
->tail
;
785 new_node
->parent
= node
;
786 if (!node
->firstchild
)
788 node
->firstchild
= new_node
;
791 if (g_img_iterator_tail
)
793 g_img_iterator_tail
->next
= new_node
;
794 g_img_iterator_tail
= new_node
;
798 g_img_iterator_head
.next
= new_node
;
799 g_img_iterator_tail
= new_node
;
805 debug("Find a file %s\n", filename
);
811 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
815 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
819 #ifdef GRUB_MACHINE_EFI
820 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
830 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
835 img
= grub_zalloc(sizeof(img_info
));
839 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
841 for (i
= 0; i
< (int)len
; i
++)
843 if (filename
[i
] == ' ' || filename
[i
] == '\t' || (0 == grub_isprint(filename
[i
])))
850 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
852 img
->size
= info
->size
;
855 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
858 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
860 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
865 if (g_ventoy_img_list
)
867 tail
= *(node
->tail
);
873 g_ventoy_img_list
= img
;
876 img
->id
= g_ventoy_img_count
;
878 if (node
&& NULL
== node
->firstiso
)
880 node
->firstiso
= img
;
891 *((img_info
**)(node
->tail
)) = img
;
892 g_ventoy_img_count
++;
894 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
895 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
898 img
->class = g_menu_class
[type
];
900 img
->menu_prefix
= g_menu_prefix
[type
];
902 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
909 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
911 int len
= GRUB_UINT_MAX
;
912 const char *value
= NULL
;
915 char guidstr
[32] = {0};
916 ventoy_guid guid
= VENTOY_GUID
;
917 const char *fmt1
= NULL
;
918 const char *fmt2
= NULL
;
919 const char *fmt3
= NULL
;
920 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
921 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
922 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
923 const char fmtcode
[]={
924 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
925 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
926 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
927 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
928 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
929 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
932 grub_memset(name
, 0, sizeof(name
));
933 puint
[0] = grub_swap_bytes32(0x56454e54);
934 puint
[3] = grub_swap_bytes32(0x4f4e0000);
935 puint
[2] = grub_swap_bytes32(0x45525349);
936 puint
[1] = grub_swap_bytes32(0x4f595f56);
937 value
= ventoy_get_env(name
);
939 grub_memset(name
, 0, sizeof(name
));
940 puint
[1] = grub_swap_bytes32(0x5f544f50);
941 puint
[0] = grub_swap_bytes32(0x56544c45);
942 fmt1
= ventoy_get_env(name
);
948 grub_memset(name
, 0, sizeof(name
));
949 puint
[1] = grub_swap_bytes32(0x5f4c4654);
950 puint
[0] = grub_swap_bytes32(0x56544c45);
951 fmt2
= ventoy_get_env(name
);
953 grub_memset(name
, 0, sizeof(name
));
954 puint
[1] = grub_swap_bytes32(0x5f434c52);
955 puint
[0] = grub_swap_bytes32(0x56544c45);
956 fmt3
= ventoy_get_env(name
);
958 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
960 #if defined (GRUB_MACHINE_EFI)
961 puint2
[0] = grub_swap_bytes32(0x55454649);
963 puint2
[0] = grub_swap_bytes32(0x42494f53);
966 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
967 #pragma GCC diagnostic push
968 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
969 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
970 fmt1
? fmt1
: fmtdata
,
971 fmt2
? fmt2
: fmtdata
+ 4,
972 value
? value
: "", plat
, guidstr
,
973 fmt3
? fmt3
: fmtdata
+ 6);
974 #pragma GCC diagnostic pop
976 grub_memset(name
, 0, sizeof(name
));
977 puint
[0] = grub_swap_bytes32(0x76746f79);
978 puint
[2] = grub_swap_bytes32(0x656e7365);
979 puint
[1] = grub_swap_bytes32(0x5f6c6963);
980 ventoy_set_env(name
, guidstr
);
985 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
987 img_info
*minimg
= NULL
;
988 img_info
*img
= (img_info
*)(node
->firstiso
);
990 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
992 if (img
->select
== 0 && (NULL
== minimg
|| grub_strcmp(img
->name
, minimg
->name
) < 0))
1007 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1009 img_iterator_node
*Minchild
= NULL
;
1010 img_iterator_node
*child
= node
->firstchild
;
1012 while (child
&& child
->parent
== node
)
1014 if (child
->select
== 0 && (NULL
== Minchild
|| grub_strcmp(child
->dir
, Minchild
->dir
) < 0))
1018 child
= child
->next
;
1023 Minchild
->select
= 1;
1029 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1032 img_info
*img
= NULL
;
1033 const char *dir_class
= NULL
;
1034 const char *dir_alias
= NULL
;
1035 img_iterator_node
*child
= NULL
;
1037 if (node
->isocnt
== 0 || node
->done
== 1)
1042 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1044 offset
= node
->parent
->dirlen
;
1047 if (node
== &g_img_iterator_head
)
1049 if (g_default_menu_mode
== 0)
1051 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1052 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1053 " echo 'return ...' \n"
1059 node
->dir
[node
->dirlen
- 1] = 0;
1060 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1063 dir_class
= "vtoydir";
1066 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1069 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1070 "submenu \"%-10s %s\" --class=\"%s\" {\n",
1071 "DIR", dir_alias
, dir_class
);
1075 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1076 "submenu \"%-10s [%s]\" --class=\"%s\" {\n",
1077 "DIR", node
->dir
+ offset
, dir_class
);
1080 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1081 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1082 " echo 'return ...' \n"
1086 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1088 ventoy_dynamic_tree_menu(child
);
1091 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1093 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1094 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1097 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1098 img
->unsupport
? "[unsupported] " : "",
1099 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1101 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1104 if (node
!= &g_img_iterator_head
)
1106 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1113 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1117 grub_device_t dev
= NULL
;
1118 img_info
*cur
= NULL
;
1119 img_info
*tail
= NULL
;
1120 img_info
*default_node
= NULL
;
1121 const char *strdata
= NULL
;
1122 char *device_name
= NULL
;
1123 const char *default_image
= NULL
;
1126 img_iterator_node
*node
= NULL
;
1127 img_iterator_node
*tmp
= NULL
;
1133 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1136 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1138 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1141 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1142 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1144 g_filt_dot_underscore_file
= 1;
1147 device_name
= grub_file_get_device_name(args
[0]);
1153 g_enum_dev
= dev
= grub_device_open(device_name
);
1159 g_enum_fs
= fs
= grub_fs_probe(dev
);
1165 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1167 debug("unsupported fs:<%s>\n", fs
->name
);
1168 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1172 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1173 if (strdata
&& strdata
[0] == '1')
1175 g_default_menu_mode
= 1;
1178 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1180 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1182 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1183 if (strdata
&& strdata
[0] == '/')
1185 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1186 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1188 g_img_iterator_head
.dir
[len
++] = '/';
1190 g_img_iterator_head
.dirlen
= len
;
1194 g_img_iterator_head
.dirlen
= 1;
1195 grub_strcpy(g_img_iterator_head
.dir
, "/");
1198 g_img_iterator_head
.tail
= &tail
;
1200 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1202 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1205 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1207 ventoy_dynamic_tree_menu(node
);
1211 node
= g_img_iterator_head
.next
;
1219 /* sort image list by image name */
1220 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1222 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1224 if (ventoy_cmp_img(cur
, tail
) > 0)
1226 ventoy_swap_img(cur
, tail
);
1231 if (g_default_menu_mode
== 1)
1233 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1234 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1235 " echo 'return ...' \n"
1239 if (g_default_menu_mode
== 0)
1241 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1244 img_len
= grub_strlen(default_image
);
1248 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1250 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1251 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1254 cur
->unsupport
? "[unsupported] " : "",
1255 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1257 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1259 if (g_default_menu_mode
== 0 && default_image
&& default_node
== NULL
)
1261 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1270 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1273 g_list_script_buf
[g_list_script_pos
] = 0;
1275 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1276 grub_env_set(args
[1], buf
);
1280 check_free(device_name
, grub_free
);
1281 check_free(dev
, grub_device_close
);
1283 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1287 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1289 img_info
*next
= NULL
;
1290 img_info
*cur
= g_ventoy_img_list
;
1303 g_ventoy_img_list
= NULL
;
1304 g_ventoy_img_count
= 0;
1306 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1309 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1312 img_info
*cur
= g_ventoy_img_list
;
1316 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1318 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1321 img_id
= grub_strtol(args
[0], NULL
, 10);
1322 if (img_id
>= g_ventoy_img_count
)
1324 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1327 debug("Find image %ld name \n", img_id
);
1329 while (cur
&& img_id
> 0)
1337 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
1340 debug("image name is %s\n", cur
->name
);
1342 grub_env_set(args
[1], cur
->name
);
1344 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1347 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1351 const char *id
= NULL
;
1352 img_info
*cur
= g_ventoy_img_list
;
1358 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
1361 id
= grub_env_get("chosen");
1363 pos
= grub_strstr(id
, "VID_");
1366 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
1370 img_id
= (int)grub_strtoul(id
, NULL
, 10);
1375 if (img_id
== cur
->id
)
1384 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
1387 grub_env_set(args
[0], cur
->path
);
1389 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1392 static int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
)
1399 device_name
= grub_file_get_device_name(filename
);
1411 pos2
= grub_strstr(pos
, ",");
1414 pos2
= grub_strstr(pos
, ")");
1422 disk
= grub_disk_open(pos
);
1425 grub_disk_read(disk
, 0, 0x180, 16, guid
);
1426 grub_disk_close(disk
);
1433 grub_free(device_name
);
1437 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
1439 eltorito_descriptor desc
;
1441 grub_memset(&desc
, 0, sizeof(desc
));
1442 grub_file_seek(file
, 17 * 2048);
1443 grub_file_read(file
, &desc
, sizeof(desc
));
1445 if (desc
.type
!= 0 || desc
.version
!= 1)
1450 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
1451 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
1459 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
1463 grub_uint8_t buf
[512];
1465 grub_file_seek(file
, sector
* 2048);
1466 grub_file_read(file
, buf
, sizeof(buf
));
1468 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
1470 debug("%s efi eltorito in Validation Entry\n", file
->name
);
1474 if (buf
[0] == 0x01 && buf
[1] == 0x00)
1479 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
1481 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
1483 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1487 if (buf
[i
] == 0x91 && buf
[i
+ 1] == 0x00 && x86count
== 1)
1489 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1494 debug("%s does not contain efi eltorito\n", file
->name
);
1498 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
1501 const char *fs
= NULL
;
1502 const char *cdprompt
= NULL
;
1504 grub_uint8_t chksum
= 0;
1507 disk
= file
->device
->disk
;
1508 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
1510 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
1511 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
1512 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
1514 pos
= grub_strstr(file
->name
, "/");
1520 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
1522 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
);
1524 param
->vtoy_img_size
= file
->size
;
1526 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
1527 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
1529 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
1531 /* Windows CD/DVD prompt 0:suppress 1:reserved */
1532 param
->vtoy_reserved
[4] = 0;
1533 if (g_ventoy_chain_type
== 1) /* Windows */
1535 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1536 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
1538 param
->vtoy_reserved
[4] = 1;
1542 fs
= ventoy_get_env("ventoy_fs_probe");
1543 if (fs
&& grub_strcmp(fs
, "udf") == 0)
1545 param
->vtoy_reserved
[3] = 1;
1548 /* calculate checksum */
1549 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1551 chksum
+= *((grub_uint8_t
*)param
+ i
);
1553 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
1558 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1560 grub_uint32_t i
= 0;
1561 grub_uint64_t total
= 0;
1562 ventoy_img_chunk
*chunk
= NULL
;
1564 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1566 chunk
= chunklist
->chunk
+ i
;
1568 if (chunk
->disk_start_sector
<= start
)
1570 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
1574 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
1577 if (total
!= ((file
->size
+ 511) / 512))
1579 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
1586 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1589 grub_uint32_t i
= 0;
1590 grub_uint32_t sector
= 0;
1591 grub_uint32_t count
= 0;
1592 grub_off_t size
= 0;
1593 grub_off_t read
= 0;
1595 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
1596 if (fs_type
== ventoy_fs_exfat
)
1598 grub_fat_get_file_chunk(start
, file
, chunklist
);
1600 else if (fs_type
== ventoy_fs_ext
)
1602 grub_ext_get_file_chunk(start
, file
, chunklist
);
1606 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
1607 file
->read_hook_data
= chunklist
;
1609 for (size
= file
->size
; size
> 0; size
-= read
)
1611 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
1612 grub_file_read(file
, NULL
, read
);
1615 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
1617 chunklist
->chunk
[i
].disk_start_sector
+= start
;
1618 chunklist
->chunk
[i
].disk_end_sector
+= start
;
1621 if (ventoy_fs_udf
== fs_type
)
1623 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1625 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
1626 chunklist
->chunk
[i
].img_start_sector
= sector
;
1627 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
1636 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1640 grub_disk_addr_t start
;
1645 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1648 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1651 if (g_img_chunk_list
.chunk
)
1653 grub_free(g_img_chunk_list
.chunk
);
1656 /* get image chunk data */
1657 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
1658 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1659 if (NULL
== g_img_chunk_list
.chunk
)
1661 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1664 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
1665 g_img_chunk_list
.cur_chunk
= 0;
1667 start
= file
->device
->disk
->partition
->start
;
1669 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
1671 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
1672 grub_file_close(file
);
1676 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
1679 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
1680 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1683 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1688 char configfile
[128];
1689 install_template
*node
= NULL
;
1695 debug("select auto installation argc:%d\n", argc
);
1702 node
= ventoy_plugin_find_install_template(args
[0]);
1705 debug("Auto install template not found for %s\n", args
[0]);
1709 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
1711 node
->cursel
= node
->autosel
- 1;
1712 debug("Auto install template auto select %d\n", node
->autosel
);
1716 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1722 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
1723 " echo %s\n}\n", "123");
1725 for (i
= 0; i
< node
->templatenum
; i
++)
1727 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1729 node
->templatepath
[i
].path
);
1732 g_ventoy_menu_esc
= 1;
1733 g_ventoy_suppress_esc
= 1;
1735 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1736 grub_script_execute_sourcecode(configfile
);
1738 g_ventoy_menu_esc
= 0;
1739 g_ventoy_suppress_esc
= 0;
1743 node
->cursel
= g_ventoy_last_entry
- 1;
1745 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1748 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1753 char configfile
[128];
1754 persistence_config
*node
;
1760 debug("select persistence argc:%d\n", argc
);
1767 node
= ventoy_plugin_find_persistent(args
[0]);
1770 debug("Persistence image not found for %s\n", args
[0]);
1774 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
1776 node
->cursel
= node
->autosel
- 1;
1777 debug("Persistence image auto select %d\n", node
->autosel
);
1781 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1787 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
1788 " echo %s\n}\n", "123");
1790 for (i
= 0; i
< node
->backendnum
; i
++)
1792 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1794 node
->backendpath
[i
].path
);
1798 g_ventoy_menu_esc
= 1;
1799 g_ventoy_suppress_esc
= 1;
1801 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1802 grub_script_execute_sourcecode(configfile
);
1804 g_ventoy_menu_esc
= 0;
1805 g_ventoy_suppress_esc
= 0;
1809 node
->cursel
= g_ventoy_last_entry
- 1;
1811 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1814 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1817 ventoy_img_chunk
*cur
;
1823 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
1825 cur
= g_img_chunk_list
.chunk
+ i
;
1826 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1827 cur
->img_start_sector
, cur
->img_end_sector
,
1828 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
1832 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1835 #ifdef GRUB_MACHINE_EFI
1836 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1844 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1847 ulong chain_len
= 0;
1848 char *chain_data
= NULL
;
1849 char *relocator_addr
= NULL
;
1850 grub_relocator_chunk_t ch
;
1851 struct grub_relocator
*relocator
= NULL
;
1852 char envbuf
[64] = { 0 };
1863 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
1864 chain_len
= grub_strtoul(args
[1], NULL
, 10);
1866 relocator
= grub_relocator_new ();
1869 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
1873 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
1874 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1878 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
1879 grub_relocator_unload (relocator
);
1883 relocator_addr
= get_virtual_current_address(ch
);
1885 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
1887 grub_relocator_unload (relocator
);
1889 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
1890 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
1892 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1896 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1900 ventoy_img_chunk_list chunklist
;
1905 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1908 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1911 /* get image chunk data */
1912 grub_memset(&chunklist
, 0, sizeof(chunklist
));
1913 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1914 if (NULL
== chunklist
.chunk
)
1916 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1919 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
1920 chunklist
.cur_chunk
= 0;
1922 ventoy_get_block_list(file
, &chunklist
, 0);
1924 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
1926 grub_printf("########## UNSUPPORTED ###############\n");
1929 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
1931 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1933 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1934 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
1937 grub_printf("\n==================================\n");
1939 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1941 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
1942 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
1943 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
1944 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1945 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
1949 grub_free(chunklist
.chunk
);
1950 grub_file_close(file
);
1952 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1955 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1958 ventoy_grub_param_file_replace
*replace
= NULL
;
1966 replace
= &(g_grub_param
->file_replace
);
1967 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
1969 replace
->old_name_cnt
= 0;
1970 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
1972 replace
->old_name_cnt
++;
1973 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
1976 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
1979 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1982 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1990 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
1991 grub_printf("%s", g_list_script_buf
);
1995 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
1996 grub_printf("%s", g_tree_script_buf
);
2002 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2004 img_info
*cur
= g_ventoy_img_list
;
2012 grub_printf("path:<%s> id=%d\n", cur
->path
, cur
->id
);
2013 grub_printf("name:<%s>\n\n", cur
->name
);
2020 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2026 ventoy_plugin_dump_auto_install();
2031 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2037 ventoy_plugin_dump_persistence();
2042 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2053 if (args
[0][0] == '0')
2055 return g_ventoy_memdisk_mode
? 0 : 1;
2057 else if (args
[0][0] == '1')
2059 return g_ventoy_iso_raw
? 0 : 1;
2061 else if (args
[0][0] == '2')
2063 return g_ventoy_iso_uefi_drv
? 0 : 1;
2069 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2071 static int configfile_mode
= 0;
2072 char memfile
[128] = {0};
2079 * args[0]: 0:normal 1:configfile
2080 * args[1]: 0:list_buf 1:tree_buf
2085 debug("Invalid argc %d\n", argc
);
2089 if (args
[0][0] == '0')
2091 if (args
[1][0] == '0')
2093 grub_script_execute_sourcecode(g_list_script_buf
);
2097 grub_script_execute_sourcecode(g_tree_script_buf
);
2102 if (configfile_mode
)
2104 debug("Now already in F3 mode %d\n", configfile_mode
);
2108 if (args
[1][0] == '0')
2110 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2111 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2115 g_ventoy_last_entry
= -1;
2116 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2117 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2120 configfile_mode
= 1;
2121 grub_script_execute_sourcecode(memfile
);
2122 configfile_mode
= 0;
2128 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2139 g_ventoy_case_insensitive
= 1;
2140 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2141 g_ventoy_case_insensitive
= 0;
2147 grub_file_close(file
);
2153 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2158 const char *isopath
= NULL
;
2160 ventoy_mbr_head mbr
;
2167 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2170 isopath
= grub_env_get("vtoy_iso_part");
2173 debug("isopath is null %p\n", isopath
);
2177 debug("isopath is %s\n", isopath
);
2179 for (id
= 0; id
< 30 && (find
== 0); id
++)
2181 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2182 if (grub_strstr(isopath
, hdname
))
2184 debug("skip %s ...\n", hdname
);
2188 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2190 disk
= grub_disk_open(hdname
);
2193 debug("%s not exist\n", hdname
);
2197 grub_memset(&mbr
, 0, sizeof(mbr
));
2198 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2200 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2202 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2203 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2206 grub_env_set(args
[0], hdname
);
2210 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
2214 debug("read %s failed\n", hdname
);
2217 grub_disk_close(disk
);
2223 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
2225 grub_uint64_t size
= 0;
2228 char fullpath
[256] = {0};
2231 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2234 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
2237 debug("grub_file_open failed <%s>\n", fullpath
);
2243 grub_file_close(file
);
2247 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
2251 char fullpath
[256] = {0};
2254 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2257 file
= grub_file_open(fullpath
, type
);
2260 debug("grub_file_open failed <%s>\n", fullpath
);
2267 int ventoy_is_file_exist(const char *fmt
, ...)
2272 char buf
[256] = {0};
2274 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
2278 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
2281 grub_strncpy(pos
+ len
, " ]", 2);
2283 debug("script exec %s\n", buf
);
2285 if (0 == grub_script_execute_sourcecode(buf
))
2293 int ventoy_is_dir_exist(const char *fmt
, ...)
2298 char buf
[256] = {0};
2300 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
2304 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
2307 grub_strncpy(pos
+ len
, " ]", 2);
2309 debug("script exec %s\n", buf
);
2311 if (0 == grub_script_execute_sourcecode(buf
))
2319 static int ventoy_env_init(void)
2323 grub_env_set("vtdebug_flag", "");
2325 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2326 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2328 ventoy_filt_register(0, ventoy_wrapper_open
);
2330 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
2333 g_grub_param
->grub_env_get
= grub_env_get
;
2334 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
2335 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
2336 grub_env_set("env_param", buf
);
2342 static cmd_para ventoy_cmds
[] =
2344 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
2345 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2346 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2347 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
2348 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
2349 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
2350 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
2351 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
2352 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
2353 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
2354 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
2355 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
2356 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
2357 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
2358 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
2359 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
2360 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
2361 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
2362 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
2363 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
2364 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
2365 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
2366 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
2367 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
2369 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
2370 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
2371 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
2372 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem
, 0, NULL
, "", "", NULL
},
2374 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2375 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2376 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
2377 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
2378 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
2379 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
2380 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
2381 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
2382 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
2383 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
2385 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
2386 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
2387 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
2388 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
2389 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
2390 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
2391 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
2393 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
2394 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
2395 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
2396 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
2399 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
2400 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
2406 GRUB_MOD_INIT(ventoy
)
2409 cmd_para
*cur
= NULL
;
2413 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2415 cur
= ventoy_cmds
+ i
;
2416 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
2417 cur
->summary
, cur
->description
, cur
->parser
);
2421 GRUB_MOD_FINI(ventoy
)
2425 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2427 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);