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_strstr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
317 return (grub_strstr(args
[0], args
[1])) ? 0 : 1;
320 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
325 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
327 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
330 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
335 value_long
+= grub_strtol(args
[1], NULL
, 10);
337 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
338 grub_env_set(args
[0], buf
);
340 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
343 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
358 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
361 debug("failed to open file <%s> for udf check\n", args
[0]);
365 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
367 grub_env_set(args
[1], buf
);
369 grub_file_close(file
);
375 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
383 g_wimboot_enable
= 0;
384 grub_check_free(g_wimiso_path
);
385 grub_check_free(g_wimiso_chunk_list
.chunk
);
387 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
393 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
394 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
395 if (NULL
== g_wimiso_chunk_list
.chunk
)
397 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
400 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
401 g_wimiso_chunk_list
.cur_chunk
= 0;
403 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
405 g_wimboot_enable
= 1;
406 g_wimiso_path
= grub_strdup(args
[0]);
408 grub_file_close(file
);
413 static grub_err_t
ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
430 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
433 debug("failed to open file <%s> for udf check\n", args
[0]);
437 #ifdef GRUB_MACHINE_EFI
438 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
440 buf
= (char *)grub_malloc(file
->size
);
443 grub_file_read(file
, buf
, file
->size
);
445 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
446 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
447 grub_env_set(name
, value
);
449 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
450 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
451 grub_env_set(name
, value
);
453 grub_file_close(file
);
459 static grub_err_t
ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt
, int argc
, char **args
)
468 if (args
[0][0] == '1')
470 grub_iso9660_set_nojoliet(1);
474 grub_iso9660_set_nojoliet(0);
480 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
485 grub_uint8_t buf
[32];
496 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
499 debug("failed to open file <%s> for udf check\n", args
[0]);
503 for (i
= 16; i
< 32; i
++)
505 grub_file_seek(file
, i
* 2048);
506 grub_file_read(file
, buf
, sizeof(buf
));
514 grub_file_seek(file
, i
* 2048);
515 grub_file_read(file
, buf
, sizeof(buf
));
517 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
520 grub_file_seek(file
, i
* 2048);
521 grub_file_read(file
, buf
, sizeof(buf
));
523 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
524 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
530 grub_file_close(file
);
532 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
537 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
539 long value_long1
= 0;
540 long value_long2
= 0;
542 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
544 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
547 value_long1
= grub_strtol(args
[0], NULL
, 10);
548 value_long2
= grub_strtol(args
[2], NULL
, 10);
550 if (0 == grub_strcmp(args
[1], "eq"))
552 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
554 else if (0 == grub_strcmp(args
[1], "ne"))
556 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
558 else if (0 == grub_strcmp(args
[1], "gt"))
560 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
562 else if (0 == grub_strcmp(args
[1], "lt"))
564 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
566 else if (0 == grub_strcmp(args
[1], "ge"))
568 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
570 else if (0 == grub_strcmp(args
[1], "le"))
572 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
576 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
582 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
589 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
592 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
593 pos
= grub_strstr(buf
, ",");
599 grub_env_set(args
[1], buf
);
601 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
604 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
610 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
616 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
619 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
621 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
622 if (0 == grub_script_execute_sourcecode(buf
))
624 debug("file %s exist, ventoy_compatible YES\n", buf
);
625 grub_env_set("ventoy_compatible", "YES");
626 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
630 debug("file %s NOT exist\n", buf
);
634 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
635 pos
= grub_strstr(buf
, ")");
641 disk
= grub_disk_open(buf
);
644 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
645 grub_disk_close(disk
);
647 g_img_swap_tmp_buf
[703] = 0;
648 for (i
= 319; i
< 703; i
++)
650 if (g_img_swap_tmp_buf
[i
] == 'V' &&
651 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
653 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
654 grub_env_set("ventoy_compatible", "YES");
655 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
661 debug("failed to open disk <%s>\n", buf
);
664 grub_env_set("ventoy_compatible", "NO");
665 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
668 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
674 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
679 if (grub_islower(c1
))
684 if (grub_islower(c2
))
698 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
700 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
702 grub_memcpy(img1
, img2
, sizeof(img_info
));
703 img1
->next
= g_img_swap_tmp
.next
;
704 img1
->prev
= g_img_swap_tmp
.prev
;
706 g_img_swap_tmp
.next
= img2
->next
;
707 g_img_swap_tmp
.prev
= img2
->prev
;
708 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
711 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
715 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
720 for (i
= 0; i
< namelen
; i
++)
722 if (filename
[i
] == ' ' || filename
[i
] == '\t')
727 if ((grub_uint8_t
)(filename
[i
]) >= 127)
736 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
740 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
750 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
758 img_iterator_node
*tmp
;
759 img_iterator_node
*new_node
;
760 img_iterator_node
*node
= (img_iterator_node
*)data
;
762 len
= grub_strlen(filename
);
766 if ((len
== 1 && filename
[0] == '.') ||
767 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
772 if (!ventoy_img_name_valid(filename
, len
))
777 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
782 new_node
= grub_zalloc(sizeof(img_iterator_node
));
785 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
787 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
790 debug("Directory %s ignored...\n", new_node
->dir
);
795 new_node
->tail
= node
->tail
;
797 new_node
->parent
= node
;
798 if (!node
->firstchild
)
800 node
->firstchild
= new_node
;
803 if (g_img_iterator_tail
)
805 g_img_iterator_tail
->next
= new_node
;
806 g_img_iterator_tail
= new_node
;
810 g_img_iterator_head
.next
= new_node
;
811 g_img_iterator_tail
= new_node
;
817 debug("Find a file %s\n", filename
);
823 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
827 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
831 #ifdef GRUB_MACHINE_EFI
832 else if (0 == grub_strcasecmp(filename
+ len
- 4, ".efi"))
842 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
847 img
= grub_zalloc(sizeof(img_info
));
851 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
853 for (i
= 0; i
< (int)len
; i
++)
855 if (filename
[i
] == ' ' || filename
[i
] == '\t' || (0 == grub_isprint(filename
[i
])))
862 img
->pathlen
= grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
864 img
->size
= info
->size
;
867 img
->size
= ventoy_grub_get_file_size("%s/%s%s", g_iso_path
, node
->dir
, filename
);
870 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
872 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
877 if (g_ventoy_img_list
)
879 tail
= *(node
->tail
);
885 g_ventoy_img_list
= img
;
888 img
->id
= g_ventoy_img_count
;
890 if (node
&& NULL
== node
->firstiso
)
892 node
->firstiso
= img
;
903 *((img_info
**)(node
->tail
)) = img
;
904 g_ventoy_img_count
++;
906 img
->alias
= ventoy_plugin_get_menu_alias(vtoy_alias_image_file
, img
->path
);
907 img
->class = ventoy_plugin_get_menu_class(vtoy_class_image_file
, img
->name
);
910 img
->class = g_menu_class
[type
];
912 img
->menu_prefix
= g_menu_prefix
[type
];
914 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
921 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
923 int len
= GRUB_UINT_MAX
;
924 const char *value
= NULL
;
927 char guidstr
[32] = {0};
928 ventoy_guid guid
= VENTOY_GUID
;
929 const char *fmt1
= NULL
;
930 const char *fmt2
= NULL
;
931 const char *fmt3
= NULL
;
932 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
933 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
934 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
935 const char fmtcode
[]={
936 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
937 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
938 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
939 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
940 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
941 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
944 grub_memset(name
, 0, sizeof(name
));
945 puint
[0] = grub_swap_bytes32(0x56454e54);
946 puint
[3] = grub_swap_bytes32(0x4f4e0000);
947 puint
[2] = grub_swap_bytes32(0x45525349);
948 puint
[1] = grub_swap_bytes32(0x4f595f56);
949 value
= ventoy_get_env(name
);
951 grub_memset(name
, 0, sizeof(name
));
952 puint
[1] = grub_swap_bytes32(0x5f544f50);
953 puint
[0] = grub_swap_bytes32(0x56544c45);
954 fmt1
= ventoy_get_env(name
);
960 grub_memset(name
, 0, sizeof(name
));
961 puint
[1] = grub_swap_bytes32(0x5f4c4654);
962 puint
[0] = grub_swap_bytes32(0x56544c45);
963 fmt2
= ventoy_get_env(name
);
965 grub_memset(name
, 0, sizeof(name
));
966 puint
[1] = grub_swap_bytes32(0x5f434c52);
967 puint
[0] = grub_swap_bytes32(0x56544c45);
968 fmt3
= ventoy_get_env(name
);
970 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
972 #if defined (GRUB_MACHINE_EFI)
973 puint2
[0] = grub_swap_bytes32(0x55454649);
975 puint2
[0] = grub_swap_bytes32(0x42494f53);
978 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
979 #pragma GCC diagnostic push
980 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
981 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
982 fmt1
? fmt1
: fmtdata
,
983 fmt2
? fmt2
: fmtdata
+ 4,
984 value
? value
: "", plat
, guidstr
,
985 fmt3
? fmt3
: fmtdata
+ 6);
986 #pragma GCC diagnostic pop
988 grub_memset(name
, 0, sizeof(name
));
989 puint
[0] = grub_swap_bytes32(0x76746f79);
990 puint
[2] = grub_swap_bytes32(0x656e7365);
991 puint
[1] = grub_swap_bytes32(0x5f6c6963);
992 ventoy_set_env(name
, guidstr
);
997 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
999 img_info
*minimg
= NULL
;
1000 img_info
*img
= (img_info
*)(node
->firstiso
);
1002 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
1004 if (img
->select
== 0 && (NULL
== minimg
|| grub_strcmp(img
->name
, minimg
->name
) < 0))
1019 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
1021 img_iterator_node
*Minchild
= NULL
;
1022 img_iterator_node
*child
= node
->firstchild
;
1024 while (child
&& child
->parent
== node
)
1026 if (child
->select
== 0 && (NULL
== Minchild
|| grub_strcmp(child
->dir
, Minchild
->dir
) < 0))
1030 child
= child
->next
;
1035 Minchild
->select
= 1;
1041 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
1044 img_info
*img
= NULL
;
1045 const char *dir_class
= NULL
;
1046 const char *dir_alias
= NULL
;
1047 img_iterator_node
*child
= NULL
;
1049 if (node
->isocnt
== 0 || node
->done
== 1)
1054 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
1056 offset
= node
->parent
->dirlen
;
1059 if (node
== &g_img_iterator_head
)
1061 if (g_default_menu_mode
== 0)
1063 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1064 "menuentry \"%-10s [Return to ListView]\" --class=\"vtoyret\" VTOY_RET {\n "
1065 " echo 'return ...' \n"
1071 node
->dir
[node
->dirlen
- 1] = 0;
1072 dir_class
= ventoy_plugin_get_menu_class(vtoy_class_directory
, node
->dir
);
1075 dir_class
= "vtoydir";
1078 dir_alias
= ventoy_plugin_get_menu_alias(vtoy_alias_directory
, node
->dir
);
1081 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1082 "submenu \"%-10s %s\" --class=\"%s\" {\n",
1083 "DIR", dir_alias
, dir_class
);
1087 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1088 "submenu \"%-10s [%s]\" --class=\"%s\" {\n",
1089 "DIR", node
->dir
+ offset
, dir_class
);
1092 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1093 "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n "
1094 " echo 'return ...' \n"
1098 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1100 ventoy_dynamic_tree_menu(child
);
1103 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1105 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1106 "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1109 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1110 img
->unsupport
? "[unsupported] " : "",
1111 img
->alias
? img
->alias
: img
->name
, img
->class, img
->id
,
1113 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1116 if (node
!= &g_img_iterator_head
)
1118 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1125 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1129 grub_device_t dev
= NULL
;
1130 img_info
*cur
= NULL
;
1131 img_info
*tail
= NULL
;
1132 img_info
*default_node
= NULL
;
1133 const char *strdata
= NULL
;
1134 char *device_name
= NULL
;
1135 const char *default_image
= NULL
;
1138 img_iterator_node
*node
= NULL
;
1139 img_iterator_node
*tmp
= NULL
;
1145 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1148 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1150 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1153 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1154 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1156 g_filt_dot_underscore_file
= 1;
1159 device_name
= grub_file_get_device_name(args
[0]);
1165 g_enum_dev
= dev
= grub_device_open(device_name
);
1171 g_enum_fs
= fs
= grub_fs_probe(dev
);
1177 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1179 debug("unsupported fs:<%s>\n", fs
->name
);
1180 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1184 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1185 if (strdata
&& strdata
[0] == '1')
1187 g_default_menu_mode
= 1;
1190 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1192 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1194 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1195 if (strdata
&& strdata
[0] == '/')
1197 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1198 if (g_img_iterator_head
.dir
[len
- 1] != '/')
1200 g_img_iterator_head
.dir
[len
++] = '/';
1202 g_img_iterator_head
.dirlen
= len
;
1206 g_img_iterator_head
.dirlen
= 1;
1207 grub_strcpy(g_img_iterator_head
.dir
, "/");
1210 g_img_iterator_head
.tail
= &tail
;
1212 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1214 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1217 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1219 ventoy_dynamic_tree_menu(node
);
1223 node
= g_img_iterator_head
.next
;
1231 /* sort image list by image name */
1232 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1234 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1236 if (ventoy_cmp_img(cur
, tail
) > 0)
1238 ventoy_swap_img(cur
, tail
);
1243 if (g_default_menu_mode
== 1)
1245 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1246 "menuentry \"%s [Return to TreeView]\" --class=\"vtoyret\" VTOY_RET {\n "
1247 " echo 'return ...' \n"
1251 if (g_default_menu_mode
== 0)
1253 default_image
= ventoy_get_env("VTOY_DEFAULT_IMAGE");
1256 img_len
= grub_strlen(default_image
);
1260 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1262 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1263 "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n"
1266 cur
->unsupport
? "[unsupported] " : "",
1267 cur
->alias
? cur
->alias
: cur
->name
, cur
->class, cur
->id
,
1269 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1271 if (g_default_menu_mode
== 0 && default_image
&& default_node
== NULL
)
1273 if (img_len
== cur
->pathlen
&& grub_strcmp(default_image
, cur
->path
) == 0)
1282 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
, "set default='VID_%d'\n", default_node
->id
);
1285 g_list_script_buf
[g_list_script_pos
] = 0;
1287 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1288 grub_env_set(args
[1], buf
);
1292 check_free(device_name
, grub_free
);
1293 check_free(dev
, grub_device_close
);
1295 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1299 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1301 img_info
*next
= NULL
;
1302 img_info
*cur
= g_ventoy_img_list
;
1315 g_ventoy_img_list
= NULL
;
1316 g_ventoy_img_count
= 0;
1318 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1321 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1324 img_info
*cur
= g_ventoy_img_list
;
1328 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1330 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1333 img_id
= grub_strtol(args
[0], NULL
, 10);
1334 if (img_id
>= g_ventoy_img_count
)
1336 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1339 debug("Find image %ld name \n", img_id
);
1341 while (cur
&& img_id
> 0)
1349 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
1352 debug("image name is %s\n", cur
->name
);
1354 grub_env_set(args
[1], cur
->name
);
1356 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1359 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1363 const char *id
= NULL
;
1364 img_info
*cur
= g_ventoy_img_list
;
1370 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
1373 id
= grub_env_get("chosen");
1375 pos
= grub_strstr(id
, "VID_");
1378 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
1382 img_id
= (int)grub_strtoul(id
, NULL
, 10);
1387 if (img_id
== cur
->id
)
1396 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
1399 grub_env_set(args
[0], cur
->path
);
1401 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1404 int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
)
1411 device_name
= grub_file_get_device_name(filename
);
1423 pos2
= grub_strstr(pos
, ",");
1426 pos2
= grub_strstr(pos
, ")");
1434 disk
= grub_disk_open(pos
);
1437 grub_disk_read(disk
, 0, 0x180, 16, guid
);
1438 grub_disk_close(disk
);
1445 grub_free(device_name
);
1449 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
1451 eltorito_descriptor desc
;
1453 grub_memset(&desc
, 0, sizeof(desc
));
1454 grub_file_seek(file
, 17 * 2048);
1455 grub_file_read(file
, &desc
, sizeof(desc
));
1457 if (desc
.type
!= 0 || desc
.version
!= 1)
1462 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
1463 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
1471 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
1475 grub_uint8_t buf
[512];
1477 grub_file_seek(file
, sector
* 2048);
1478 grub_file_read(file
, buf
, sizeof(buf
));
1480 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
1482 debug("%s efi eltorito in Validation Entry\n", file
->name
);
1486 if (buf
[0] == 0x01 && buf
[1] == 0x00)
1491 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
1493 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
1495 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1499 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0x00 && x86count
== 1)
1501 debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1506 debug("%s does not contain efi eltorito\n", file
->name
);
1510 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
1513 const char *fs
= NULL
;
1514 const char *cdprompt
= NULL
;
1516 grub_uint8_t chksum
= 0;
1519 disk
= file
->device
->disk
;
1520 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
1522 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
1523 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
1524 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
1526 pos
= grub_strstr(file
->name
, "/");
1532 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
1534 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
);
1536 param
->vtoy_img_size
= file
->size
;
1538 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
1539 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
1541 param
->vtoy_reserved
[2] = g_ventoy_chain_type
;
1543 /* Windows CD/DVD prompt 0:suppress 1:reserved */
1544 param
->vtoy_reserved
[4] = 0;
1545 if (g_ventoy_chain_type
== 1) /* Windows */
1547 cdprompt
= ventoy_get_env("VTOY_WINDOWS_CD_PROMPT");
1548 if (cdprompt
&& cdprompt
[0] == '1' && cdprompt
[1] == 0)
1550 param
->vtoy_reserved
[4] = 1;
1554 fs
= ventoy_get_env("ventoy_fs_probe");
1555 if (fs
&& grub_strcmp(fs
, "udf") == 0)
1557 param
->vtoy_reserved
[3] = 1;
1560 /* calculate checksum */
1561 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1563 chksum
+= *((grub_uint8_t
*)param
+ i
);
1565 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
1570 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1572 grub_uint32_t i
= 0;
1573 grub_uint64_t total
= 0;
1574 ventoy_img_chunk
*chunk
= NULL
;
1576 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1578 chunk
= chunklist
->chunk
+ i
;
1580 if (chunk
->disk_start_sector
<= start
)
1582 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
1586 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
1589 if (total
!= ((file
->size
+ 511) / 512))
1591 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
1598 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1601 grub_uint32_t i
= 0;
1602 grub_uint32_t sector
= 0;
1603 grub_uint32_t count
= 0;
1604 grub_off_t size
= 0;
1605 grub_off_t read
= 0;
1607 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
1608 if (fs_type
== ventoy_fs_exfat
)
1610 grub_fat_get_file_chunk(start
, file
, chunklist
);
1612 else if (fs_type
== ventoy_fs_ext
)
1614 grub_ext_get_file_chunk(start
, file
, chunklist
);
1618 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
1619 file
->read_hook_data
= chunklist
;
1621 for (size
= file
->size
; size
> 0; size
-= read
)
1623 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
1624 grub_file_read(file
, NULL
, read
);
1627 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
1629 chunklist
->chunk
[i
].disk_start_sector
+= start
;
1630 chunklist
->chunk
[i
].disk_end_sector
+= start
;
1633 if (ventoy_fs_udf
== fs_type
)
1635 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1637 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
1638 chunklist
->chunk
[i
].img_start_sector
= sector
;
1639 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
1648 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1652 grub_disk_addr_t start
;
1657 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1660 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1663 if (g_img_chunk_list
.chunk
)
1665 grub_free(g_img_chunk_list
.chunk
);
1668 /* get image chunk data */
1669 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
1670 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1671 if (NULL
== g_img_chunk_list
.chunk
)
1673 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1676 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
1677 g_img_chunk_list
.cur_chunk
= 0;
1679 start
= file
->device
->disk
->partition
->start
;
1681 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
1683 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
1684 grub_file_close(file
);
1688 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
1691 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
1692 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1695 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1700 char configfile
[128];
1701 install_template
*node
= NULL
;
1707 debug("select auto installation argc:%d\n", argc
);
1714 node
= ventoy_plugin_find_install_template(args
[0]);
1717 debug("Auto install template not found for %s\n", args
[0]);
1721 if (node
->autosel
>= 0 && node
->autosel
<= node
->templatenum
)
1723 node
->cursel
= node
->autosel
- 1;
1724 debug("Auto install template auto select %d\n", node
->autosel
);
1728 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1734 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
1735 " echo %s\n}\n", "123");
1737 for (i
= 0; i
< node
->templatenum
; i
++)
1739 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1741 node
->templatepath
[i
].path
);
1744 g_ventoy_menu_esc
= 1;
1745 g_ventoy_suppress_esc
= 1;
1747 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1748 grub_script_execute_sourcecode(configfile
);
1750 g_ventoy_menu_esc
= 0;
1751 g_ventoy_suppress_esc
= 0;
1755 node
->cursel
= g_ventoy_last_entry
- 1;
1757 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1760 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1765 char configfile
[128];
1766 persistence_config
*node
;
1772 debug("select persistence argc:%d\n", argc
);
1779 node
= ventoy_plugin_find_persistent(args
[0]);
1782 debug("Persistence image not found for %s\n", args
[0]);
1786 if (node
->autosel
>= 0 && node
->autosel
<= node
->backendnum
)
1788 node
->cursel
= node
->autosel
- 1;
1789 debug("Persistence image auto select %d\n", node
->autosel
);
1793 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1799 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
1800 " echo %s\n}\n", "123");
1802 for (i
= 0; i
< node
->backendnum
; i
++)
1804 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1806 node
->backendpath
[i
].path
);
1810 g_ventoy_menu_esc
= 1;
1811 g_ventoy_suppress_esc
= 1;
1813 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1814 grub_script_execute_sourcecode(configfile
);
1816 g_ventoy_menu_esc
= 0;
1817 g_ventoy_suppress_esc
= 0;
1821 node
->cursel
= g_ventoy_last_entry
- 1;
1823 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1826 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1829 ventoy_img_chunk
*cur
;
1835 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
1837 cur
= g_img_chunk_list
.chunk
+ i
;
1838 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1839 cur
->img_start_sector
, cur
->img_end_sector
,
1840 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
1844 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1847 #ifdef GRUB_MACHINE_EFI
1848 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1856 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1859 ulong chain_len
= 0;
1860 char *chain_data
= NULL
;
1861 char *relocator_addr
= NULL
;
1862 grub_relocator_chunk_t ch
;
1863 struct grub_relocator
*relocator
= NULL
;
1864 char envbuf
[64] = { 0 };
1875 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
1876 chain_len
= grub_strtoul(args
[1], NULL
, 10);
1878 relocator
= grub_relocator_new ();
1881 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
1885 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
1886 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1890 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
1891 grub_relocator_unload (relocator
);
1895 relocator_addr
= get_virtual_current_address(ch
);
1897 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
1899 grub_relocator_unload (relocator
);
1901 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
1902 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
1904 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1908 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1912 ventoy_img_chunk_list chunklist
;
1917 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1920 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1923 /* get image chunk data */
1924 grub_memset(&chunklist
, 0, sizeof(chunklist
));
1925 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1926 if (NULL
== chunklist
.chunk
)
1928 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1931 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
1932 chunklist
.cur_chunk
= 0;
1934 ventoy_get_block_list(file
, &chunklist
, 0);
1936 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
1938 grub_printf("########## UNSUPPORTED ###############\n");
1941 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
1943 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1945 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1946 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
1949 grub_printf("\n==================================\n");
1951 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1953 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
1954 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
1955 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
1956 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1957 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
1961 grub_free(chunklist
.chunk
);
1962 grub_file_close(file
);
1964 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1967 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1970 ventoy_grub_param_file_replace
*replace
= NULL
;
1978 replace
= &(g_grub_param
->file_replace
);
1979 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
1981 replace
->old_name_cnt
= 0;
1982 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
1984 replace
->old_name_cnt
++;
1985 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
1988 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
1991 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1994 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2002 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2003 grub_printf("%s", g_list_script_buf
);
2007 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
2008 grub_printf("%s", g_tree_script_buf
);
2014 static grub_err_t
ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2016 img_info
*cur
= g_ventoy_img_list
;
2024 grub_printf("path:<%s> id=%d\n", cur
->path
, cur
->id
);
2025 grub_printf("name:<%s>\n\n", cur
->name
);
2032 static grub_err_t
ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2038 ventoy_plugin_dump_injection();
2043 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2049 ventoy_plugin_dump_auto_install();
2054 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2060 ventoy_plugin_dump_persistence();
2065 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2076 if (args
[0][0] == '0')
2078 return g_ventoy_memdisk_mode
? 0 : 1;
2080 else if (args
[0][0] == '1')
2082 return g_ventoy_iso_raw
? 0 : 1;
2084 else if (args
[0][0] == '2')
2086 return g_ventoy_iso_uefi_drv
? 0 : 1;
2092 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2094 static int configfile_mode
= 0;
2095 char memfile
[128] = {0};
2102 * args[0]: 0:normal 1:configfile
2103 * args[1]: 0:list_buf 1:tree_buf
2108 debug("Invalid argc %d\n", argc
);
2112 if (args
[0][0] == '0')
2114 if (args
[1][0] == '0')
2116 grub_script_execute_sourcecode(g_list_script_buf
);
2120 grub_script_execute_sourcecode(g_tree_script_buf
);
2125 if (configfile_mode
)
2127 debug("Now already in F3 mode %d\n", configfile_mode
);
2131 if (args
[1][0] == '0')
2133 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2134 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
2138 g_ventoy_last_entry
= -1;
2139 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
2140 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
2143 configfile_mode
= 1;
2144 grub_script_execute_sourcecode(memfile
);
2145 configfile_mode
= 0;
2151 static grub_err_t
ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2162 g_ventoy_case_insensitive
= 1;
2163 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
2164 g_ventoy_case_insensitive
= 0;
2170 grub_file_close(file
);
2176 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2181 const char *isopath
= NULL
;
2183 ventoy_mbr_head mbr
;
2190 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
2193 isopath
= grub_env_get("vtoy_iso_part");
2196 debug("isopath is null %p\n", isopath
);
2200 debug("isopath is %s\n", isopath
);
2202 for (id
= 0; id
< 30 && (find
== 0); id
++)
2204 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
2205 if (grub_strstr(isopath
, hdname
))
2207 debug("skip %s ...\n", hdname
);
2211 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2213 disk
= grub_disk_open(hdname
);
2216 debug("%s not exist\n", hdname
);
2220 grub_memset(&mbr
, 0, sizeof(mbr
));
2221 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2223 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2225 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2226 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2229 grub_env_set(args
[0], hdname
);
2233 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
2237 debug("read %s failed\n", hdname
);
2240 grub_disk_close(disk
);
2246 static grub_err_t
ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2257 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s file var \n", cmd_raw_name
);
2260 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2263 debug("failed to open file %s\n", args
[0]);
2267 buf
= grub_malloc(len
);
2274 grub_file_read(file
, buf
, len
- 1);
2276 ventoy_get_line(buf
);
2277 ventoy_set_env(args
[1], buf
);
2281 grub_check_free(buf
);
2282 grub_file_close(file
);
2287 static grub_err_t
ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2292 ventoy_iso9660_vd pvd
;
2299 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s sysid volid \n", cmd_raw_name
);
2302 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2305 debug("failed to open file %s\n", args
[0]);
2309 grub_file_seek(file
, 16 * 2048);
2310 len
= (int)grub_file_read(file
, &pvd
, sizeof(pvd
));
2311 if (len
!= sizeof(pvd
))
2313 debug("failed to read pvd %d\n", len
);
2317 grub_memset(buf
, 0, sizeof(buf
));
2318 grub_memcpy(buf
, pvd
.sys
, sizeof(pvd
.sys
));
2319 ventoy_set_env(args
[1], buf
);
2321 grub_memset(buf
, 0, sizeof(buf
));
2322 grub_memcpy(buf
, pvd
.vol
, sizeof(pvd
.vol
));
2323 ventoy_set_env(args
[2], buf
);
2326 grub_file_close(file
);
2331 static grub_err_t
ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt
, int argc
, char **args
)
2342 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s var \n", cmd_raw_name
);
2345 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
2348 debug("failed to open file %s\n", args
[0]);
2352 grub_memset(buf
, 0, sizeof(buf
));
2353 grub_file_seek(file
, 16 * 2048 + 813);
2354 len
= (int)grub_file_read(file
, buf
, 17);
2357 debug("failed to read create date %d\n", len
);
2361 ventoy_set_env(args
[1], buf
);
2364 grub_file_close(file
);
2369 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
2371 grub_uint64_t size
= 0;
2374 char fullpath
[256] = {0};
2377 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2380 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
2383 debug("grub_file_open failed <%s>\n", fullpath
);
2389 grub_file_close(file
);
2393 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
2397 char fullpath
[256] = {0};
2400 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2403 file
= grub_file_open(fullpath
, type
);
2406 debug("grub_file_open failed <%s>\n", fullpath
);
2413 int ventoy_is_file_exist(const char *fmt
, ...)
2418 char buf
[256] = {0};
2420 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
2424 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
2427 grub_strncpy(pos
+ len
, " ]", 2);
2429 debug("script exec %s\n", buf
);
2431 if (0 == grub_script_execute_sourcecode(buf
))
2439 int ventoy_is_dir_exist(const char *fmt
, ...)
2444 char buf
[256] = {0};
2446 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -d ");
2450 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
2453 grub_strncpy(pos
+ len
, " ]", 2);
2455 debug("script exec %s\n", buf
);
2457 if (0 == grub_script_execute_sourcecode(buf
))
2465 static int ventoy_env_init(void)
2469 grub_env_set("vtdebug_flag", "");
2471 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2472 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2474 ventoy_filt_register(0, ventoy_wrapper_open
);
2476 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
2479 g_grub_param
->grub_env_get
= grub_env_get
;
2480 g_grub_param
->grub_env_printf
= (grub_env_printf_pf
)grub_printf
;
2481 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
2482 grub_env_set("env_param", buf
);
2488 static cmd_para ventoy_cmds
[] =
2490 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
2491 { "vt_strstr", ventoy_cmd_strstr
, 0, NULL
, "", "", NULL
},
2492 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2493 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2494 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
2495 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
2496 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
2497 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
2498 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
2499 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
2500 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
2501 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
2502 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
2503 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
2504 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
2505 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
2506 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
2507 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
2508 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
2509 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
2510 { "vt_dump_img_list", ventoy_cmd_dump_img_list
, 0, NULL
, "", "", NULL
},
2511 { "vt_dump_injection", ventoy_cmd_dump_injection
, 0, NULL
, "", "", NULL
},
2512 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
2513 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
2514 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
2515 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
2517 { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet
, 0, NULL
, "", "", NULL
},
2518 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
2519 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
2520 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem
, 0, NULL
, "", "", NULL
},
2522 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2523 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2524 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
2525 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
2526 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
2527 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
2528 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
2529 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
2530 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
2531 { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index
, 0, NULL
, "", "", NULL
},
2533 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
2534 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
2535 { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch
, 0, NULL
, "", "", NULL
},
2536 { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch
, 0, NULL
, "", "", NULL
},
2537 { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count
, 0, NULL
, "", "", NULL
},
2538 { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch
, 0, NULL
, "", "", NULL
},
2539 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
2541 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
2542 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
2543 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
2544 { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase
, 0, NULL
, "", "", NULL
},
2547 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
2548 { "vt_check_plugin_json", ventoy_cmd_plugin_check_json
, 0, NULL
, "", "", NULL
},
2550 { "vt_1st_line", ventoy_cmd_read_1st_line
, 0, NULL
, "", "", NULL
},
2551 { "vt_parse_iso_volume", ventoy_cmd_parse_volume
, 0, NULL
, "", "", NULL
},
2552 { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date
, 0, NULL
, "", "", NULL
},
2553 { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver
, 0, NULL
, "", "", NULL
},
2554 { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver
, 0, NULL
, "", "", NULL
},
2555 { "vt_unix_reset", ventoy_cmd_unix_reset
, 0, NULL
, "", "", NULL
},
2556 { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf
, 0, NULL
, "", "", NULL
},
2557 { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko
, 0, NULL
, "", "", NULL
},
2558 { "vt_unix_chain_data", ventoy_cmd_unix_chain_data
, 0, NULL
, "", "", NULL
},
2564 GRUB_MOD_INIT(ventoy
)
2567 cmd_para
*cur
= NULL
;
2571 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2573 cur
= ventoy_cmds
+ i
;
2574 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
2575 cur
->summary
, cur
->description
, cur
->parser
);
2579 GRUB_MOD_FINI(ventoy
)
2583 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2585 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);