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_cpio_buf
= NULL
;
72 grub_uint32_t g_ventoy_cpio_size
= 0;
73 cpio_newc_header
*g_ventoy_initrd_head
= NULL
;
74 grub_uint8_t
*g_ventoy_runtime_buf
= NULL
;
76 ventoy_grub_param
*g_grub_param
= NULL
;
78 ventoy_guid g_ventoy_guid
= VENTOY_GUID
;
80 ventoy_img_chunk_list g_img_chunk_list
;
82 int g_wimboot_enable
= 0;
83 ventoy_img_chunk_list g_wimiso_chunk_list
;
84 char *g_wimiso_path
= NULL
;
86 static char *g_tree_script_buf
= NULL
;
87 static int g_tree_script_pos
= 0;
89 static char *g_list_script_buf
= NULL
;
90 static int g_list_script_pos
= 0;
93 void ventoy_debug(const char *fmt
, ...)
98 grub_vprintf (fmt
, args
);
102 int ventoy_is_efi_os(void)
106 g_efi_os
= (grub_strstr(GRUB_PLATFORM
, "efi")) ? 1 : 0;
112 static int ventoy_get_fs_type(const char *fs
)
116 return ventoy_fs_max
;
118 else if (grub_strncmp(fs
, "exfat", 5) == 0)
120 return ventoy_fs_exfat
;
122 else if (grub_strncmp(fs
, "ntfs", 4) == 0)
124 return ventoy_fs_ntfs
;
126 else if (grub_strncmp(fs
, "ext", 3) == 0)
128 return ventoy_fs_ext
;
130 else if (grub_strncmp(fs
, "xfs", 3) == 0)
132 return ventoy_fs_xfs
;
134 else if (grub_strncmp(fs
, "udf", 3) == 0)
136 return ventoy_fs_udf
;
138 else if (grub_strncmp(fs
, "fat", 3) == 0)
140 return ventoy_fs_fat
;
143 return ventoy_fs_max
;
146 static int ventoy_string_check(const char *str
, grub_char_check_func check
)
165 static grub_ssize_t
ventoy_fs_read(grub_file_t file
, char *buf
, grub_size_t len
)
167 grub_memcpy(buf
, (char *)file
->data
+ file
->offset
, len
);
171 static grub_err_t
ventoy_fs_close(grub_file_t file
)
173 grub_file_close(g_old_file
);
174 grub_free(file
->data
);
182 static grub_file_t
ventoy_wrapper_open(grub_file_t rawFile
, enum grub_file_type type
)
186 static struct grub_fs vtoy_fs
=
191 .fs_read
= ventoy_fs_read
,
192 .fs_close
= ventoy_fs_close
,
202 file
= (grub_file_t
)grub_zalloc(sizeof (*file
));
208 file
->data
= grub_malloc(rawFile
->size
+ 4096);
214 grub_file_read(rawFile
, file
->data
, rawFile
->size
);
215 len
= ventoy_fill_data(4096, (char *)file
->data
+ rawFile
->size
);
217 g_old_file
= rawFile
;
219 file
->size
= rawFile
->size
+ len
;
220 file
->device
= rawFile
->device
;
222 file
->not_easily_seekable
= 1;
227 static int ventoy_check_decimal_var(const char *name
, long *value
)
229 const char *value_str
= NULL
;
231 value_str
= grub_env_get(name
);
232 if (NULL
== value_str
)
234 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s not found", name
);
237 if (!ventoy_is_decimal(value_str
))
239 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Variable %s value '%s' is not an integer", name
, value_str
);
242 *value
= grub_strtol(value_str
, NULL
, 10);
244 return GRUB_ERR_NONE
;
247 static grub_err_t
ventoy_cmd_debug(grub_extcmd_context_t ctxt
, int argc
, char **args
)
251 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {on|off}", cmd_raw_name
);
254 if (0 == grub_strcmp(args
[0], "on"))
257 grub_env_set("vtdebug_flag", "debug");
262 grub_env_set("vtdebug_flag", "");
265 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
268 static grub_err_t
ventoy_cmd_break(grub_extcmd_context_t ctxt
, int argc
, char **args
)
272 if (argc
< 1 || (args
[0][0] != '0' && args
[0][0] != '1'))
274 grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name
);
275 grub_printf(" level:\r\n");
276 grub_printf(" 01/11: busybox / (+cat log)\r\n");
277 grub_printf(" 02/12: initrd / (+cat log)\r\n");
278 grub_printf(" 03/13: hook / (+cat log)\r\n");
280 grub_printf(" debug:\r\n");
281 grub_printf(" 0: debug is on\r\n");
282 grub_printf(" 1: debug is off\r\n");
284 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
287 g_ventoy_break_level
= (grub_uint8_t
)grub_strtoul(args
[0], NULL
, 16);
289 if (argc
> 1 && grub_strtoul(args
[1], NULL
, 10) > 0)
291 g_ventoy_debug_level
= 1;
294 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
297 static grub_err_t
ventoy_cmd_incr(grub_extcmd_context_t ctxt
, int argc
, char **args
)
302 if ((argc
!= 2) || (!ventoy_is_decimal(args
[1])))
304 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Variable} {Int}", cmd_raw_name
);
307 if (GRUB_ERR_NONE
!= ventoy_check_decimal_var(args
[0], &value_long
))
312 value_long
+= grub_strtol(args
[1], NULL
, 10);
314 grub_snprintf(buf
, sizeof(buf
), "%ld", value_long
);
315 grub_env_set(args
[0], buf
);
317 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
320 static grub_err_t
ventoy_cmd_file_size(grub_extcmd_context_t ctxt
, int argc
, char **args
)
335 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
338 debug("failed to open file <%s> for udf check\n", args
[0]);
342 grub_snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)file
->size
);
344 grub_env_set(args
[1], buf
);
346 grub_file_close(file
);
352 static grub_err_t
ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt
, int argc
, char **args
)
360 g_wimboot_enable
= 0;
361 grub_check_free(g_wimiso_path
);
362 grub_check_free(g_wimiso_chunk_list
.chunk
);
364 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
370 grub_memset(&g_wimiso_chunk_list
, 0, sizeof(g_wimiso_chunk_list
));
371 g_wimiso_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
372 if (NULL
== g_wimiso_chunk_list
.chunk
)
374 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
377 g_wimiso_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
378 g_wimiso_chunk_list
.cur_chunk
= 0;
380 ventoy_get_block_list(file
, &g_wimiso_chunk_list
, file
->device
->disk
->partition
->start
);
382 g_wimboot_enable
= 1;
383 g_wimiso_path
= grub_strdup(args
[0]);
385 grub_file_close(file
);
390 static grub_err_t
ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt
, int argc
, char **args
)
407 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
410 debug("failed to open file <%s> for udf check\n", args
[0]);
414 #ifdef GRUB_MACHINE_EFI
415 buf
= (char *)grub_efi_allocate_iso_buf(file
->size
);
417 buf
= (char *)grub_malloc(file
->size
);
420 grub_file_read(file
, buf
, file
->size
);
422 grub_snprintf(name
, sizeof(name
), "%s_addr", args
[1]);
423 grub_snprintf(value
, sizeof(value
), "0x%llx", (unsigned long long)(unsigned long)buf
);
424 grub_env_set(name
, value
);
426 grub_snprintf(name
, sizeof(name
), "%s_size", args
[1]);
427 grub_snprintf(value
, sizeof(value
), "%llu", (unsigned long long)file
->size
);
428 grub_env_set(name
, value
);
430 grub_file_close(file
);
436 static grub_err_t
ventoy_cmd_is_udf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
441 grub_uint8_t buf
[32];
452 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
455 debug("failed to open file <%s> for udf check\n", args
[0]);
459 for (i
= 16; i
< 32; i
++)
461 grub_file_seek(file
, i
* 2048);
462 grub_file_read(file
, buf
, sizeof(buf
));
470 grub_file_seek(file
, i
* 2048);
471 grub_file_read(file
, buf
, sizeof(buf
));
473 if (grub_memcmp(buf
+ 1, "BEA01", 5) == 0)
476 grub_file_seek(file
, i
* 2048);
477 grub_file_read(file
, buf
, sizeof(buf
));
479 if (grub_memcmp(buf
+ 1, "NSR02", 5) == 0 ||
480 grub_memcmp(buf
+ 1, "NSR03", 5) == 0)
486 grub_file_close(file
);
488 debug("ISO UDF: %s\n", rc
? "NO" : "YES");
493 static grub_err_t
ventoy_cmd_cmp(grub_extcmd_context_t ctxt
, int argc
, char **args
)
495 long value_long1
= 0;
496 long value_long2
= 0;
498 if ((argc
!= 3) || (!ventoy_is_decimal(args
[0])) || (!ventoy_is_decimal(args
[2])))
500 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name
);
503 value_long1
= grub_strtol(args
[0], NULL
, 10);
504 value_long2
= grub_strtol(args
[2], NULL
, 10);
506 if (0 == grub_strcmp(args
[1], "eq"))
508 grub_errno
= (value_long1
== value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
510 else if (0 == grub_strcmp(args
[1], "ne"))
512 grub_errno
= (value_long1
!= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
514 else if (0 == grub_strcmp(args
[1], "gt"))
516 grub_errno
= (value_long1
> value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
518 else if (0 == grub_strcmp(args
[1], "lt"))
520 grub_errno
= (value_long1
< value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
522 else if (0 == grub_strcmp(args
[1], "ge"))
524 grub_errno
= (value_long1
>= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
526 else if (0 == grub_strcmp(args
[1], "le"))
528 grub_errno
= (value_long1
<= value_long2
) ? GRUB_ERR_NONE
: GRUB_ERR_TEST_FAILURE
;
532 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name
);
538 static grub_err_t
ventoy_cmd_device(grub_extcmd_context_t ctxt
, int argc
, char **args
)
545 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s path var", cmd_raw_name
);
548 grub_strncpy(buf
, (args
[0][0] == '(') ? args
[0] + 1 : args
[0], sizeof(buf
) - 1);
549 pos
= grub_strstr(buf
, ",");
555 grub_env_set(args
[1], buf
);
557 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
560 static grub_err_t
ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt
, int argc
, char **args
)
566 const char *files
[] = { "ventoy.dat", "VENTOY.DAT" };
572 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s (loop)", cmd_raw_name
);
575 for (i
= 0; i
< (int)ARRAY_SIZE(files
); i
++)
577 grub_snprintf(buf
, sizeof(buf
) - 1, "[ -e %s/%s ]", args
[0], files
[i
]);
578 if (0 == grub_script_execute_sourcecode(buf
))
580 debug("file %s exist, ventoy_compatible YES\n", buf
);
581 grub_env_set("ventoy_compatible", "YES");
582 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
586 debug("file %s NOT exist\n", buf
);
590 grub_snprintf(buf
, sizeof(buf
) - 1, "%s", args
[0][0] == '(' ? (args
[0] + 1) : args
[0]);
591 pos
= grub_strstr(buf
, ")");
597 disk
= grub_disk_open(buf
);
600 grub_disk_read(disk
, 16 << 2, 0, 1024, g_img_swap_tmp_buf
);
601 grub_disk_close(disk
);
603 g_img_swap_tmp_buf
[703] = 0;
604 for (i
= 319; i
< 703; i
++)
606 if (g_img_swap_tmp_buf
[i
] == 'V' &&
607 0 == grub_strncmp(g_img_swap_tmp_buf
+ i
, VENTOY_COMPATIBLE_STR
, VENTOY_COMPATIBLE_STR_LEN
))
609 debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i
);
610 grub_env_set("ventoy_compatible", "YES");
611 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
617 debug("failed to open disk <%s>\n", buf
);
620 grub_env_set("ventoy_compatible", "NO");
621 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
624 int ventoy_cmp_img(img_info
*img1
, img_info
*img2
)
630 for (s1
= img1
->name
, s2
= img2
->name
; *s1
&& *s2
; s1
++, s2
++)
635 if (grub_islower(c1
))
640 if (grub_islower(c2
))
654 void ventoy_swap_img(img_info
*img1
, img_info
*img2
)
656 grub_memcpy(&g_img_swap_tmp
, img1
, sizeof(img_info
));
658 grub_memcpy(img1
, img2
, sizeof(img_info
));
659 img1
->next
= g_img_swap_tmp
.next
;
660 img1
->prev
= g_img_swap_tmp
.prev
;
662 g_img_swap_tmp
.next
= img2
->next
;
663 g_img_swap_tmp
.prev
= img2
->prev
;
664 grub_memcpy(img2
, &g_img_swap_tmp
, sizeof(img_info
));
667 static int ventoy_img_name_valid(const char *filename
, grub_size_t namelen
)
671 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
676 for (i
= 0; i
< namelen
; i
++)
678 if (filename
[i
] == ' ' || filename
[i
] == '\t')
683 if ((grub_uint8_t
)(filename
[i
]) >= 127)
692 static int ventoy_check_ignore_flag(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
696 if (filename
&& filename
[0] == '.' && 0 == grub_strncmp(filename
, ".ventoyignore", 13))
706 static int ventoy_colect_img_files(const char *filename
, const struct grub_dirhook_info
*info
, void *data
)
714 img_iterator_node
*tmp
;
715 img_iterator_node
*new_node
;
716 img_iterator_node
*node
= (img_iterator_node
*)data
;
718 len
= grub_strlen(filename
);
722 if ((len
== 1 && filename
[0] == '.') ||
723 (len
== 2 && filename
[0] == '.' && filename
[1] == '.'))
728 if (!ventoy_img_name_valid(filename
, len
))
733 if (filename
[0] == '$' && 0 == grub_strncmp(filename
, "$RECYCLE.BIN", 12))
738 new_node
= grub_zalloc(sizeof(img_iterator_node
));
741 new_node
->dirlen
= grub_snprintf(new_node
->dir
, sizeof(new_node
->dir
), "%s%s/", node
->dir
, filename
);
743 g_enum_fs
->fs_dir(g_enum_dev
, new_node
->dir
, ventoy_check_ignore_flag
, &ignore
);
746 debug("Directory %s ignored...\n", new_node
->dir
);
751 new_node
->tail
= node
->tail
;
753 new_node
->parent
= node
;
754 if (!node
->firstchild
)
756 node
->firstchild
= new_node
;
759 if (g_img_iterator_tail
)
761 g_img_iterator_tail
->next
= new_node
;
762 g_img_iterator_tail
= new_node
;
766 g_img_iterator_head
.next
= new_node
;
767 g_img_iterator_tail
= new_node
;
773 debug("Find a file %s\n", filename
);
779 if (0 == grub_strcasecmp(filename
+ len
- 4, ".iso"))
783 else if (g_wimboot_enable
&& (0 == grub_strcasecmp(filename
+ len
- 4, ".wim")))
792 if (g_filt_dot_underscore_file
&& filename
[0] == '.' && filename
[1] == '_')
797 img
= grub_zalloc(sizeof(img_info
));
801 grub_snprintf(img
->name
, sizeof(img
->name
), "%s", filename
);
803 for (i
= 0; i
< (int)len
; i
++)
805 if (filename
[i
] == ' ' || filename
[i
] == '\t' || (0 == grub_isprint(filename
[i
])))
812 grub_snprintf(img
->path
, sizeof(img
->path
), "%s%s", node
->dir
, img
->name
);
814 img
->size
= info
->size
;
817 img
->size
= ventoy_grub_get_file_size("%s/%s", g_iso_path
, img
->path
);
820 if (img
->size
< VTOY_FILT_MIN_FILE_SIZE
)
822 debug("img <%s> size too small %llu\n", img
->name
, (ulonglong
)img
->size
);
827 if (g_ventoy_img_list
)
829 tail
= *(node
->tail
);
835 g_ventoy_img_list
= img
;
838 img
->id
= g_ventoy_img_count
;
840 if (node
&& NULL
== node
->firstiso
)
842 node
->firstiso
= img
;
853 *((img_info
**)(node
->tail
)) = img
;
854 g_ventoy_img_count
++;
856 debug("Add %s%s to list %d\n", node
->dir
, filename
, g_ventoy_img_count
);
863 int ventoy_fill_data(grub_uint32_t buflen
, char *buffer
)
865 int len
= GRUB_UINT_MAX
;
866 const char *value
= NULL
;
869 char guidstr
[32] = {0};
870 ventoy_guid guid
= VENTOY_GUID
;
871 const char *fmt1
= NULL
;
872 const char *fmt2
= NULL
;
873 const char *fmt3
= NULL
;
874 grub_uint32_t
*puint
= (grub_uint32_t
*)name
;
875 grub_uint32_t
*puint2
= (grub_uint32_t
*)plat
;
876 const char fmtdata
[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 };
877 const char fmtcode
[]={
878 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70,
879 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25,
880 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78,
881 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F,
882 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E,
883 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00
886 grub_memset(name
, 0, sizeof(name
));
887 puint
[0] = grub_swap_bytes32(0x56454e54);
888 puint
[3] = grub_swap_bytes32(0x4f4e0000);
889 puint
[2] = grub_swap_bytes32(0x45525349);
890 puint
[1] = grub_swap_bytes32(0x4f595f56);
891 value
= ventoy_get_env(name
);
893 grub_memset(name
, 0, sizeof(name
));
894 puint
[1] = grub_swap_bytes32(0x5f544f50);
895 puint
[0] = grub_swap_bytes32(0x56544c45);
896 fmt1
= ventoy_get_env(name
);
902 grub_memset(name
, 0, sizeof(name
));
903 puint
[1] = grub_swap_bytes32(0x5f4c4654);
904 puint
[0] = grub_swap_bytes32(0x56544c45);
905 fmt2
= ventoy_get_env(name
);
907 grub_memset(name
, 0, sizeof(name
));
908 puint
[1] = grub_swap_bytes32(0x5f434c52);
909 puint
[0] = grub_swap_bytes32(0x56544c45);
910 fmt3
= ventoy_get_env(name
);
912 grub_memcpy(guidstr
, &guid
, sizeof(guid
));
914 #if defined (GRUB_MACHINE_EFI)
915 puint2
[0] = grub_swap_bytes32(0x55454649);
917 puint2
[0] = grub_swap_bytes32(0x42494f53);
920 /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */
921 #pragma GCC diagnostic push
922 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
923 len
= grub_snprintf(buffer
, buflen
, fmtcode
,
924 fmt1
? fmt1
: fmtdata
,
925 fmt2
? fmt2
: fmtdata
+ 4,
926 value
? value
: "", plat
, guidstr
,
927 fmt3
? fmt3
: fmtdata
+ 6);
928 #pragma GCC diagnostic pop
930 grub_memset(name
, 0, sizeof(name
));
931 puint
[0] = grub_swap_bytes32(0x76746f79);
932 puint
[2] = grub_swap_bytes32(0x656e7365);
933 puint
[1] = grub_swap_bytes32(0x5f6c6963);
934 ventoy_set_env(name
, guidstr
);
939 static img_info
* ventoy_get_min_iso(img_iterator_node
*node
)
941 img_info
*minimg
= NULL
;
942 img_info
*img
= (img_info
*)(node
->firstiso
);
944 while (img
&& (img_iterator_node
*)(img
->parent
) == node
)
946 if (img
->select
== 0 && (NULL
== minimg
|| grub_strcmp(img
->name
, minimg
->name
) < 0))
961 static img_iterator_node
* ventoy_get_min_child(img_iterator_node
*node
)
963 img_iterator_node
*Minchild
= NULL
;
964 img_iterator_node
*child
= node
->firstchild
;
966 while (child
&& child
->parent
== node
)
968 if (child
->select
== 0 && (NULL
== Minchild
|| grub_strcmp(child
->dir
, Minchild
->dir
) < 0))
977 Minchild
->select
= 1;
983 static int ventoy_dynamic_tree_menu(img_iterator_node
*node
)
987 img_iterator_node
*child
= NULL
;
989 if (node
->isocnt
== 0 || node
->done
== 1)
994 if (node
->parent
&& node
->parent
->dirlen
< node
->dirlen
)
996 offset
= node
->parent
->dirlen
;
999 if (node
== &g_img_iterator_head
)
1001 if (g_default_menu_mode
== 0)
1003 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1004 "menuentry \"%-10s [Return to ListView]\" VTOY_RET {\n "
1005 " echo 'return ...' \n"
1011 node
->dir
[node
->dirlen
- 1] = 0;
1012 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1013 "submenu \"%-10s [%s]\" {\n",
1014 "DIR", node
->dir
+ offset
);
1016 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1017 "menuentry \"%-10s [../]\" VTOY_RET {\n "
1018 " echo 'return ...' \n"
1022 while ((child
= ventoy_get_min_child(node
)) != NULL
)
1024 ventoy_dynamic_tree_menu(child
);
1027 while ((img
= ventoy_get_min_iso(node
)) != NULL
)
1029 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
,
1030 "menuentry \"%-10s %s%s\" --id=\"VID_%d\" {\n"
1033 grub_get_human_size(img
->size
, GRUB_HUMAN_SIZE_SHORT
),
1034 img
->unsupport
? "[unsupported] " : "", img
->name
, img
->id
,
1035 (img
->type
== img_type_iso
) ? "iso" : "wim",
1036 img
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1039 if (node
!= &g_img_iterator_head
)
1041 vtoy_ssprintf(g_tree_script_buf
, g_tree_script_pos
, "%s", "}\n");
1048 static grub_err_t
ventoy_cmd_list_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1052 grub_device_t dev
= NULL
;
1053 img_info
*cur
= NULL
;
1054 img_info
*tail
= NULL
;
1055 const char *strdata
= NULL
;
1056 char *device_name
= NULL
;
1058 img_iterator_node
*node
= NULL
;
1059 img_iterator_node
*tmp
= NULL
;
1065 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {device} {cntvar}", cmd_raw_name
);
1068 if (g_ventoy_img_list
|| g_ventoy_img_count
)
1070 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Must clear image before list");
1073 strdata
= ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE");
1074 if (strdata
&& strdata
[0] == '1' && strdata
[1] == 0)
1076 g_filt_dot_underscore_file
= 1;
1079 device_name
= grub_file_get_device_name(args
[0]);
1085 g_enum_dev
= dev
= grub_device_open(device_name
);
1091 g_enum_fs
= fs
= grub_fs_probe(dev
);
1097 if (ventoy_get_fs_type(fs
->name
) >= ventoy_fs_max
)
1099 debug("unsupported fs:<%s>\n", fs
->name
);
1100 ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system");
1104 strdata
= ventoy_get_env("VTOY_DEFAULT_MENU_MODE");
1105 if (strdata
&& strdata
[0] == '1')
1107 g_default_menu_mode
= 1;
1110 grub_memset(&g_img_iterator_head
, 0, sizeof(g_img_iterator_head
));
1112 grub_snprintf(g_iso_path
, sizeof(g_iso_path
), "%s", args
[0]);
1114 strdata
= ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT");
1115 if (strdata
&& strdata
[0] == '/')
1117 len
= grub_snprintf(g_img_iterator_head
.dir
, sizeof(g_img_iterator_head
.dir
) - 1, "%s", strdata
);
1118 if (g_img_iterator_head
.dir
[len
] != '/')
1120 g_img_iterator_head
.dir
[len
++] = '/';
1122 g_img_iterator_head
.dirlen
= len
;
1126 g_img_iterator_head
.dirlen
= 1;
1127 grub_strcpy(g_img_iterator_head
.dir
, "/");
1130 g_img_iterator_head
.tail
= &tail
;
1132 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1134 fs
->fs_dir(dev
, node
->dir
, ventoy_colect_img_files
, node
);
1137 for (node
= &g_img_iterator_head
; node
; node
= node
->next
)
1139 ventoy_dynamic_tree_menu(node
);
1143 node
= g_img_iterator_head
.next
;
1151 /* sort image list by image name */
1152 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1154 for (tail
= cur
->next
; tail
; tail
= tail
->next
)
1156 if (ventoy_cmp_img(cur
, tail
) > 0)
1158 ventoy_swap_img(cur
, tail
);
1163 if (g_default_menu_mode
== 1)
1165 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1166 "menuentry \"%s [Return to TreeView]\" VTOY_RET {\n "
1167 " echo 'return ...' \n"
1171 for (cur
= g_ventoy_img_list
; cur
; cur
= cur
->next
)
1173 vtoy_ssprintf(g_list_script_buf
, g_list_script_pos
,
1174 "menuentry \"%s%s\" --id=\"VID_%d\" {\n"
1177 cur
->unsupport
? "[unsupported] " : "", cur
->name
, cur
->id
,
1178 (cur
->type
== img_type_iso
) ? "iso" : "wim",
1179 cur
->unsupport
? "unsupport_menuentry" : "common_menuentry");
1181 g_list_script_buf
[g_list_script_pos
] = 0;
1183 grub_snprintf(buf
, sizeof(buf
), "%d", g_ventoy_img_count
);
1184 grub_env_set(args
[1], buf
);
1188 check_free(device_name
, grub_free
);
1189 check_free(dev
, grub_device_close
);
1191 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1195 static grub_err_t
ventoy_cmd_clear_img(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1197 img_info
*next
= NULL
;
1198 img_info
*cur
= g_ventoy_img_list
;
1211 g_ventoy_img_list
= NULL
;
1212 g_ventoy_img_count
= 0;
1214 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1217 static grub_err_t
ventoy_cmd_img_name(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1220 img_info
*cur
= g_ventoy_img_list
;
1224 if (argc
!= 2 || (!ventoy_is_decimal(args
[0])))
1226 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {imageID} {var}", cmd_raw_name
);
1229 img_id
= grub_strtol(args
[0], NULL
, 10);
1230 if (img_id
>= g_ventoy_img_count
)
1232 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images %ld %ld", img_id
, g_ventoy_img_count
);
1235 debug("Find image %ld name \n", img_id
);
1237 while (cur
&& img_id
> 0)
1245 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such many images");
1248 debug("image name is %s\n", cur
->name
);
1250 grub_env_set(args
[1], cur
->name
);
1252 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1255 static grub_err_t
ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1259 const char *id
= NULL
;
1260 img_info
*cur
= g_ventoy_img_list
;
1266 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s {var}", cmd_raw_name
);
1269 id
= grub_env_get("chosen");
1271 pos
= grub_strstr(id
, "VID_");
1274 img_id
= (int)grub_strtoul(pos
+ 4, NULL
, 10);
1278 img_id
= (int)grub_strtoul(id
, NULL
, 10);
1283 if (img_id
== cur
->id
)
1292 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "No such image");
1295 grub_env_set(args
[0], cur
->path
);
1297 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1300 static int ventoy_get_disk_guid(const char *filename
, grub_uint8_t
*guid
)
1307 device_name
= grub_file_get_device_name(filename
);
1319 pos2
= grub_strstr(pos
, ",");
1322 pos2
= grub_strstr(pos
, ")");
1330 disk
= grub_disk_open(pos
);
1333 grub_disk_read(disk
, 0, 0x180, 16, guid
);
1334 grub_disk_close(disk
);
1341 grub_free(device_name
);
1345 grub_uint32_t
ventoy_get_iso_boot_catlog(grub_file_t file
)
1347 eltorito_descriptor desc
;
1349 grub_memset(&desc
, 0, sizeof(desc
));
1350 grub_file_seek(file
, 17 * 2048);
1351 grub_file_read(file
, &desc
, sizeof(desc
));
1353 if (desc
.type
!= 0 || desc
.version
!= 1)
1358 if (grub_strncmp((char *)desc
.id
, "CD001", 5) != 0 ||
1359 grub_strncmp((char *)desc
.system_id
, "EL TORITO SPECIFICATION", 23) != 0)
1367 int ventoy_has_efi_eltorito(grub_file_t file
, grub_uint32_t sector
)
1370 grub_uint8_t buf
[512];
1372 grub_file_seek(file
, sector
* 2048);
1373 grub_file_read(file
, buf
, sizeof(buf
));
1375 if (buf
[0] == 0x01 && buf
[1] == 0xEF)
1377 debug("%s efi eltorito in Validation Entry\n", file
->name
);
1381 for (i
= 64; i
< (int)sizeof(buf
); i
+= 32)
1383 if ((buf
[i
] == 0x90 || buf
[i
] == 0x91) && buf
[i
+ 1] == 0xEF)
1385 debug("%s efi eltorito offset %d 0x%02x\n", file
->name
, i
, buf
[i
]);
1390 debug("%s does not contain efi eltorito\n", file
->name
);
1394 void ventoy_fill_os_param(grub_file_t file
, ventoy_os_param
*param
)
1398 grub_uint8_t chksum
= 0;
1401 disk
= file
->device
->disk
;
1402 grub_memcpy(¶m
->guid
, &g_ventoy_guid
, sizeof(ventoy_guid
));
1404 param
->vtoy_disk_size
= disk
->total_sectors
* (1 << disk
->log_sector_size
);
1405 param
->vtoy_disk_part_id
= disk
->partition
->number
+ 1;
1406 param
->vtoy_disk_part_type
= ventoy_get_fs_type(file
->fs
->name
);
1408 pos
= grub_strstr(file
->name
, "/");
1414 grub_snprintf(param
->vtoy_img_path
, sizeof(param
->vtoy_img_path
), "%s", pos
);
1416 ventoy_get_disk_guid(file
->name
, param
->vtoy_disk_guid
);
1418 param
->vtoy_img_size
= file
->size
;
1420 param
->vtoy_reserved
[0] = g_ventoy_break_level
;
1421 param
->vtoy_reserved
[1] = g_ventoy_debug_level
;
1423 /* calculate checksum */
1424 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1426 chksum
+= *((grub_uint8_t
*)param
+ i
);
1428 param
->chksum
= (grub_uint8_t
)(0x100 - chksum
);
1433 int ventoy_check_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1435 grub_uint32_t i
= 0;
1436 grub_uint64_t total
= 0;
1437 ventoy_img_chunk
*chunk
= NULL
;
1439 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1441 chunk
= chunklist
->chunk
+ i
;
1443 if (chunk
->disk_start_sector
<= start
)
1445 debug("%u disk start invalid %lu\n", i
, (ulong
)start
);
1449 total
+= chunk
->disk_end_sector
+ 1 - chunk
->disk_start_sector
;
1452 if (total
!= ((file
->size
+ 511) / 512))
1454 debug("Invalid total: %llu %llu\n", (ulonglong
)total
, (ulonglong
)((file
->size
+ 511) / 512));
1461 int ventoy_get_block_list(grub_file_t file
, ventoy_img_chunk_list
*chunklist
, grub_disk_addr_t start
)
1464 grub_uint32_t i
= 0;
1465 grub_uint32_t sector
= 0;
1466 grub_uint32_t count
= 0;
1467 grub_off_t size
= 0;
1468 grub_off_t read
= 0;
1470 fs_type
= ventoy_get_fs_type(file
->fs
->name
);
1471 if (fs_type
== ventoy_fs_exfat
)
1473 grub_fat_get_file_chunk(start
, file
, chunklist
);
1475 else if (fs_type
== ventoy_fs_ext
)
1477 grub_ext_get_file_chunk(start
, file
, chunklist
);
1481 file
->read_hook
= (grub_disk_read_hook_t
)grub_disk_blocklist_read
;
1482 file
->read_hook_data
= chunklist
;
1484 for (size
= file
->size
; size
> 0; size
-= read
)
1486 read
= (size
> VTOY_SIZE_1GB
) ? VTOY_SIZE_1GB
: size
;
1487 grub_file_read(file
, NULL
, read
);
1490 for (i
= 0; start
> 0 && i
< chunklist
->cur_chunk
; i
++)
1492 chunklist
->chunk
[i
].disk_start_sector
+= start
;
1493 chunklist
->chunk
[i
].disk_end_sector
+= start
;
1496 if (ventoy_fs_udf
== fs_type
)
1498 for (i
= 0; i
< chunklist
->cur_chunk
; i
++)
1500 count
= (chunklist
->chunk
[i
].disk_end_sector
+ 1 - chunklist
->chunk
[i
].disk_start_sector
) >> 2;
1501 chunklist
->chunk
[i
].img_start_sector
= sector
;
1502 chunklist
->chunk
[i
].img_end_sector
= sector
+ count
- 1;
1511 static grub_err_t
ventoy_cmd_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1515 grub_disk_addr_t start
;
1520 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1523 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1526 if (g_img_chunk_list
.chunk
)
1528 grub_free(g_img_chunk_list
.chunk
);
1531 /* get image chunk data */
1532 grub_memset(&g_img_chunk_list
, 0, sizeof(g_img_chunk_list
));
1533 g_img_chunk_list
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1534 if (NULL
== g_img_chunk_list
.chunk
)
1536 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1539 g_img_chunk_list
.max_chunk
= DEFAULT_CHUNK_NUM
;
1540 g_img_chunk_list
.cur_chunk
= 0;
1542 start
= file
->device
->disk
->partition
->start
;
1544 ventoy_get_block_list(file
, &g_img_chunk_list
, start
);
1546 rc
= ventoy_check_block_list(file
, &g_img_chunk_list
, start
);
1547 grub_file_close(file
);
1551 return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET
, "Unsupported chunk list.\n");
1554 grub_memset(&g_grub_param
->file_replace
, 0, sizeof(g_grub_param
->file_replace
));
1555 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1558 static grub_err_t
ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1563 char configfile
[128];
1564 install_template
*node
= NULL
;
1575 node
= ventoy_plugin_find_install_template(args
[0]);
1581 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1587 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without auto installation template\" {\n"
1588 " echo %s\n}\n", "123");
1590 for (i
= 0; i
< node
->templatenum
; i
++)
1592 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1594 node
->templatepath
[i
].path
);
1597 g_ventoy_menu_esc
= 1;
1598 g_ventoy_suppress_esc
= 1;
1600 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1601 grub_script_execute_sourcecode(configfile
);
1603 g_ventoy_menu_esc
= 0;
1604 g_ventoy_suppress_esc
= 0;
1608 node
->cursel
= g_ventoy_last_entry
- 1;
1610 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1613 static grub_err_t
ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1618 char configfile
[128];
1619 persistence_config
*node
;
1630 node
= ventoy_plugin_find_persistent(args
[0]);
1636 buf
= (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF
);
1642 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot without persistence\" {\n"
1643 " echo %s\n}\n", "123");
1645 for (i
= 0; i
< node
->backendnum
; i
++)
1647 vtoy_ssprintf(buf
, pos
, "menuentry \"Boot with %s\" {\n"
1649 node
->backendpath
[i
].path
);
1653 g_ventoy_menu_esc
= 1;
1654 g_ventoy_suppress_esc
= 1;
1656 grub_snprintf(configfile
, sizeof(configfile
), "configfile mem:0x%llx:size:%d", (ulonglong
)(ulong
)buf
, pos
);
1657 grub_script_execute_sourcecode(configfile
);
1659 g_ventoy_menu_esc
= 0;
1660 g_ventoy_suppress_esc
= 0;
1664 node
->cursel
= g_ventoy_last_entry
- 1;
1666 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1669 static grub_err_t
ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1672 ventoy_img_chunk
*cur
;
1678 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
1680 cur
= g_img_chunk_list
.chunk
+ i
;
1681 grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n",
1682 cur
->img_start_sector
, cur
->img_end_sector
,
1683 (unsigned long long)cur
->disk_start_sector
, (unsigned long long)cur
->disk_end_sector
1687 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1690 #ifdef GRUB_MACHINE_EFI
1691 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1699 static grub_err_t
ventoy_cmd_relocator_chaindata(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1702 ulong chain_len
= 0;
1703 char *chain_data
= NULL
;
1704 char *relocator_addr
= NULL
;
1705 grub_relocator_chunk_t ch
;
1706 struct grub_relocator
*relocator
= NULL
;
1707 char envbuf
[64] = { 0 };
1718 chain_data
= (char *)grub_strtoul(args
[0], NULL
, 16);
1719 chain_len
= grub_strtoul(args
[1], NULL
, 10);
1721 relocator
= grub_relocator_new ();
1724 debug("grub_relocator_new failed %p %lu\n", chain_data
, chain_len
);
1728 rc
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
1729 0x100000, // GRUB_LINUX_BZIMAGE_ADDR,
1733 debug("grub_relocator_alloc_chunk_addr failed %d %p %lu\n", rc
, chain_data
, chain_len
);
1734 grub_relocator_unload (relocator
);
1738 relocator_addr
= get_virtual_current_address(ch
);
1740 grub_memcpy(relocator_addr
, chain_data
, chain_len
);
1742 grub_relocator_unload (relocator
);
1744 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)relocator_addr
);
1745 grub_env_set("vtoy_chain_relocator_addr", envbuf
);
1747 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1751 static grub_err_t
ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1755 ventoy_img_chunk_list chunklist
;
1760 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1763 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
1766 /* get image chunk data */
1767 grub_memset(&chunklist
, 0, sizeof(chunklist
));
1768 chunklist
.chunk
= grub_malloc(sizeof(ventoy_img_chunk
) * DEFAULT_CHUNK_NUM
);
1769 if (NULL
== chunklist
.chunk
)
1771 return grub_error(GRUB_ERR_OUT_OF_MEMORY
, "Can't allocate image chunk memoty\n");
1774 chunklist
.max_chunk
= DEFAULT_CHUNK_NUM
;
1775 chunklist
.cur_chunk
= 0;
1777 ventoy_get_block_list(file
, &chunklist
, 0);
1779 if (0 != ventoy_check_block_list(file
, &chunklist
, 0))
1781 grub_printf("########## UNSUPPORTED ###############\n");
1784 grub_printf("filesystem: <%s> entry number:<%u>\n", file
->fs
->name
, chunklist
.cur_chunk
);
1786 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1788 grub_printf("%llu+%llu,", (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1789 (ulonglong
)(chunklist
.chunk
[i
].disk_end_sector
+ 1 - chunklist
.chunk
[i
].disk_start_sector
));
1792 grub_printf("\n==================================\n");
1794 for (i
= 0; i
< chunklist
.cur_chunk
; i
++)
1796 grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i
,
1797 (ulonglong
)chunklist
.chunk
[i
].img_start_sector
,
1798 (ulonglong
)chunklist
.chunk
[i
].img_end_sector
,
1799 (ulonglong
)chunklist
.chunk
[i
].disk_start_sector
,
1800 (ulonglong
)chunklist
.chunk
[i
].disk_end_sector
1804 grub_free(chunklist
.chunk
);
1805 grub_file_close(file
);
1807 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1810 static grub_err_t
ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1813 ventoy_grub_param_file_replace
*replace
= NULL
;
1821 replace
= &(g_grub_param
->file_replace
);
1822 replace
->magic
= GRUB_FILE_REPLACE_MAGIC
;
1824 replace
->old_name_cnt
= 0;
1825 for (i
= 0; i
< 4 && i
+ 1 < argc
; i
++)
1827 replace
->old_name_cnt
++;
1828 grub_snprintf(replace
->old_file_name
[i
], sizeof(replace
->old_file_name
[i
]), "%s", args
[i
+ 1]);
1831 replace
->new_file_virtual_id
= (grub_uint32_t
)grub_strtoul(args
[0], NULL
, 10);
1834 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1837 static grub_err_t
ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1845 grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos
, VTOY_MAX_SCRIPT_BUF
);
1846 grub_printf("%s", g_list_script_buf
);
1850 grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos
, VTOY_MAX_SCRIPT_BUF
);
1851 grub_printf("%s", g_tree_script_buf
);
1857 static grub_err_t
ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1863 ventoy_plugin_dump_auto_install();
1868 static grub_err_t
ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1874 ventoy_plugin_dump_persistence();
1879 static grub_err_t
ventoy_cmd_check_mode(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1890 if (args
[0][0] == '0')
1892 return g_ventoy_memdisk_mode
? 0 : 1;
1894 else if (args
[0][0] == '1')
1896 return g_ventoy_iso_raw
? 0 : 1;
1898 else if (args
[0][0] == '2')
1900 return g_ventoy_iso_uefi_drv
? 0 : 1;
1906 static grub_err_t
ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1908 static int configfile_mode
= 0;
1909 char memfile
[128] = {0};
1916 * args[0]: 0:normal 1:configfile
1917 * args[1]: 0:list_buf 1:tree_buf
1922 debug("Invalid argc %d\n", argc
);
1926 if (args
[0][0] == '0')
1928 if (args
[1][0] == '0')
1930 grub_script_execute_sourcecode(g_list_script_buf
);
1934 grub_script_execute_sourcecode(g_tree_script_buf
);
1939 if (configfile_mode
)
1941 debug("Now already in F3 mode %d\n", configfile_mode
);
1945 if (args
[1][0] == '0')
1947 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
1948 (ulonglong
)(ulong
)g_list_script_buf
, g_list_script_pos
);
1952 g_ventoy_last_entry
= -1;
1953 grub_snprintf(memfile
, sizeof(memfile
), "configfile mem:0x%llx:size:%d",
1954 (ulonglong
)(ulong
)g_tree_script_buf
, g_tree_script_pos
);
1957 configfile_mode
= 1;
1958 grub_script_execute_sourcecode(memfile
);
1959 configfile_mode
= 0;
1965 static grub_err_t
ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1970 const char *isopath
= NULL
;
1972 ventoy_mbr_head mbr
;
1979 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Usage: %s variable\n", cmd_raw_name
);
1982 isopath
= grub_env_get("iso_path");
1985 debug("isopath is null %p\n", isopath
);
1989 debug("isopath is %s\n", isopath
);
1991 for (id
= 0; id
< 30 && (find
== 0); id
++)
1993 grub_snprintf(hdname
, sizeof(hdname
), "hd%d,", id
);
1994 if (grub_strstr(isopath
, hdname
))
1996 debug("skip %s ...\n", hdname
);
2000 grub_snprintf(hdname
, sizeof(hdname
), "hd%d", id
);
2002 disk
= grub_disk_open(hdname
);
2005 debug("%s not exist\n", hdname
);
2009 grub_memset(&mbr
, 0, sizeof(mbr
));
2010 if (0 == grub_disk_read(disk
, 0, 0, 512, &mbr
))
2012 if (mbr
.Byte55
== 0x55 && mbr
.ByteAA
== 0xAA)
2014 if (mbr
.PartTbl
[0].Active
== 0x80 || mbr
.PartTbl
[1].Active
== 0x80 ||
2015 mbr
.PartTbl
[2].Active
== 0x80 || mbr
.PartTbl
[3].Active
== 0x80)
2018 grub_env_set(args
[0], hdname
);
2022 debug("%s is %s\n", hdname
, find
? "bootable" : "NOT bootable");
2026 debug("read %s failed\n", hdname
);
2029 grub_disk_close(disk
);
2035 grub_uint64_t
ventoy_grub_get_file_size(const char *fmt
, ...)
2037 grub_uint64_t size
= 0;
2040 char fullpath
[256] = {0};
2043 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2046 file
= grub_file_open(fullpath
, VENTOY_FILE_TYPE
);
2049 debug("grub_file_open failed <%s>\n", fullpath
);
2055 grub_file_close(file
);
2059 grub_file_t
ventoy_grub_file_open(enum grub_file_type type
, const char *fmt
, ...)
2063 char fullpath
[256] = {0};
2066 grub_vsnprintf(fullpath
, 255, fmt
, ap
);
2069 file
= grub_file_open(fullpath
, type
);
2072 debug("grub_file_open failed <%s>\n", fullpath
);
2079 int ventoy_is_file_exist(const char *fmt
, ...)
2084 char buf
[256] = {0};
2086 grub_snprintf(buf
, sizeof(buf
), "%s", "[ -f ");
2090 len
= grub_vsnprintf(pos
, 255, fmt
, ap
);
2093 grub_strncpy(pos
+ len
, " ]", 2);
2095 debug("script exec %s\n", buf
);
2097 if (0 == grub_script_execute_sourcecode(buf
))
2105 static int ventoy_env_init(void)
2109 grub_env_set("vtdebug_flag", "");
2110 grub_env_export("vtdebug_flag");
2112 g_tree_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2113 g_list_script_buf
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
2115 ventoy_filt_register(0, ventoy_wrapper_open
);
2117 g_grub_param
= (ventoy_grub_param
*)grub_zalloc(sizeof(ventoy_grub_param
));
2120 g_grub_param
->grub_env_get
= grub_env_get
;
2121 grub_snprintf(buf
, sizeof(buf
), "%p", g_grub_param
);
2122 grub_env_set("env_param", buf
);
2128 static cmd_para ventoy_cmds
[] =
2130 { "vt_incr", ventoy_cmd_incr
, 0, NULL
, "{Var} {INT}", "Increase integer variable", NULL
},
2131 { "vt_debug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2132 { "vtdebug", ventoy_cmd_debug
, 0, NULL
, "{on|off}", "turn debug on/off", NULL
},
2133 { "vtbreak", ventoy_cmd_break
, 0, NULL
, "{level}", "set debug break", NULL
},
2134 { "vt_cmp", ventoy_cmd_cmp
, 0, NULL
, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL
},
2135 { "vt_device", ventoy_cmd_device
, 0, NULL
, "path var", "", NULL
},
2136 { "vt_check_compatible", ventoy_cmd_check_compatible
, 0, NULL
, "", "", NULL
},
2137 { "vt_list_img", ventoy_cmd_list_img
, 0, NULL
, "{device} {cntvar}", "find all iso file in device", NULL
},
2138 { "vt_clear_img", ventoy_cmd_clear_img
, 0, NULL
, "", "clear image list", NULL
},
2139 { "vt_img_name", ventoy_cmd_img_name
, 0, NULL
, "{imageID} {var}", "get image name", NULL
},
2140 { "vt_chosen_img_path", ventoy_cmd_chosen_img_path
, 0, NULL
, "{var}", "get chosen img path", NULL
},
2141 { "vt_img_sector", ventoy_cmd_img_sector
, 0, NULL
, "{imageName}", "", NULL
},
2142 { "vt_dump_img_sector", ventoy_cmd_dump_img_sector
, 0, NULL
, "", "", NULL
},
2143 { "vt_load_wimboot", ventoy_cmd_load_wimboot
, 0, NULL
, "", "", NULL
},
2144 { "vt_load_cpio", ventoy_cmd_load_cpio
, 0, NULL
, "", "", NULL
},
2145 { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd
, 0, NULL
, "", "", NULL
},
2146 { "vt_dump_menu", ventoy_cmd_dump_menu
, 0, NULL
, "", "", NULL
},
2147 { "vt_dynamic_menu", ventoy_cmd_dynamic_menu
, 0, NULL
, "", "", NULL
},
2148 { "vt_check_mode", ventoy_cmd_check_mode
, 0, NULL
, "", "", NULL
},
2149 { "vt_dump_auto_install", ventoy_cmd_dump_auto_install
, 0, NULL
, "", "", NULL
},
2150 { "vt_dump_persistence", ventoy_cmd_dump_persistence
, 0, NULL
, "", "", NULL
},
2151 { "vt_select_auto_install", ventoy_cmd_sel_auto_install
, 0, NULL
, "", "", NULL
},
2152 { "vt_select_persistence", ventoy_cmd_sel_persistence
, 0, NULL
, "", "", NULL
},
2154 { "vt_is_udf", ventoy_cmd_is_udf
, 0, NULL
, "", "", NULL
},
2155 { "vt_file_size", ventoy_cmd_file_size
, 0, NULL
, "", "", NULL
},
2156 { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem
, 0, NULL
, "", "", NULL
},
2158 { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2159 { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect
, 0, NULL
, "{cfgfile}", "", NULL
},
2160 { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file
, 0, NULL
, "", "", NULL
},
2161 { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list
, 0, NULL
, "", "", NULL
},
2162 { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list
, 0, NULL
, "", "", NULL
},
2163 { "vt_linux_initrd_count", ventoy_cmd_initrd_count
, 0, NULL
, "", "", NULL
},
2164 { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count
, 0, NULL
, "", "", NULL
},
2165 { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd
, 0, NULL
, "", "", NULL
},
2166 { "vt_linux_chain_data", ventoy_cmd_linux_chain_data
, 0, NULL
, "", "", NULL
},
2168 { "vt_windows_reset", ventoy_cmd_wimdows_reset
, 0, NULL
, "", "", NULL
},
2169 { "vt_windows_locate_wim", ventoy_cmd_wimdows_locate_wim
, 0, NULL
, "", "", NULL
},
2170 { "vt_windows_chain_data", ventoy_cmd_windows_chain_data
, 0, NULL
, "", "", NULL
},
2171 { "vt_wim_chain_data", ventoy_cmd_wim_chain_data
, 0, NULL
, "", "", NULL
},
2173 { "vt_add_replace_file", ventoy_cmd_add_replace_file
, 0, NULL
, "", "", NULL
},
2174 { "vt_relocator_chaindata", ventoy_cmd_relocator_chaindata
, 0, NULL
, "", "", NULL
},
2175 { "vt_test_block_list", ventoy_cmd_test_block_list
, 0, NULL
, "", "", NULL
},
2178 { "vt_load_plugin", ventoy_cmd_load_plugin
, 0, NULL
, "", "", NULL
},
2183 GRUB_MOD_INIT(ventoy
)
2186 cmd_para
*cur
= NULL
;
2190 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2192 cur
= ventoy_cmds
+ i
;
2193 cur
->cmd
= grub_register_extcmd(cur
->name
, cur
->func
, cur
->flags
,
2194 cur
->summary
, cur
->description
, cur
->parser
);
2198 GRUB_MOD_FINI(ventoy
)
2202 for (i
= 0; i
< ARRAY_SIZE(ventoy_cmds
); i
++)
2204 grub_unregister_extcmd(ventoy_cmds
[i
].cmd
);